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, configElement, ConfigSubsection, configSequence, configElementBoolean, configSelection, configElement_nonSave, getConfigListEntry
20 from Components.config import configfile, configsequencearg
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 ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import *
40 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
47 from Components.config import config, currentConfigSelectionElement
50 from Menu import MainMenu, mdom
54 self.dishDialog = self.session.instantiateDialog(Dish)
55 self.onLayoutFinish.append(self.dishDialog.show)
57 class InfoBarShowHide:
58 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
66 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
68 "toggleShow": self.toggleShow,
72 self.__state = self.STATE_SHOWN
75 self.onExecBegin.append(self.show)
77 self.hideTimer = eTimer()
78 self.hideTimer.timeout.get().append(self.doTimerHide)
79 self.hideTimer.start(5000, True)
81 self.onShow.append(self.__onShow)
82 self.onHide.append(self.__onHide)
85 self.__state = self.STATE_SHOWN
88 def startHideTimer(self):
89 if self.__state == self.STATE_SHOWN and not self.__locked:
90 self.hideTimer.start(5000, True)
93 self.__state = self.STATE_HIDDEN
99 def doTimerHide(self):
100 self.hideTimer.stop()
101 if self.__state == self.STATE_SHOWN:
104 def toggleShow(self):
105 if self.__state == self.STATE_SHOWN:
107 self.hideTimer.stop()
108 elif self.__state == self.STATE_HIDDEN:
112 self.__locked = self.__locked + 1
115 self.hideTimer.stop()
117 def unlockShow(self):
118 self.__locked = self.__locked - 1
120 self.startHideTimer()
122 # def startShow(self):
123 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
124 # self.__state = self.STATE_SHOWN
126 # def startHide(self):
127 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
128 # self.__state = self.STATE_HIDDEN
130 class NumberZap(Screen):
137 self.close(int(self["number"].getText()))
139 def keyNumberGlobal(self, number):
140 self.Timer.start(3000, True) #reset timer
141 self.field = self.field + str(number)
142 self["number"].setText(self.field)
143 if len(self.field) >= 4:
146 def __init__(self, session, number):
147 Screen.__init__(self, session)
148 self.field = str(number)
150 self["channel"] = Label(_("Channel:"))
152 self["number"] = Label(self.field)
154 self["actions"] = NumberActionMap( [ "SetupActions" ],
158 "1": self.keyNumberGlobal,
159 "2": self.keyNumberGlobal,
160 "3": self.keyNumberGlobal,
161 "4": self.keyNumberGlobal,
162 "5": self.keyNumberGlobal,
163 "6": self.keyNumberGlobal,
164 "7": self.keyNumberGlobal,
165 "8": self.keyNumberGlobal,
166 "9": self.keyNumberGlobal,
167 "0": self.keyNumberGlobal
170 self.Timer = eTimer()
171 self.Timer.timeout.get().append(self.keyOK)
172 self.Timer.start(3000, True)
174 class InfoBarNumberZap:
175 """ Handles an initial number for NumberZapping """
177 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
179 "1": self.keyNumberGlobal,
180 "2": self.keyNumberGlobal,
181 "3": self.keyNumberGlobal,
182 "4": self.keyNumberGlobal,
183 "5": self.keyNumberGlobal,
184 "6": self.keyNumberGlobal,
185 "7": self.keyNumberGlobal,
186 "8": self.keyNumberGlobal,
187 "9": self.keyNumberGlobal,
188 "0": self.keyNumberGlobal,
191 def keyNumberGlobal(self, number):
192 # print "You pressed number " + str(number)
194 self.servicelist.recallPrevService()
197 self.session.openWithCallback(self.numberEntered, NumberZap, number)
199 def numberEntered(self, retval):
200 # print self.servicelist
202 self.zapToNumber(retval)
204 def searchNumberHelper(self, serviceHandler, num, bouquet):
205 servicelist = serviceHandler.list(bouquet)
206 if not servicelist is None:
208 serviceIterator = servicelist.getNext()
209 if not serviceIterator.valid(): #check end of list
211 if serviceIterator.flags: #assume normal dvb service have no flags set
214 if not num: #found service with searched number ?
215 return serviceIterator, 0
218 def zapToNumber(self, number):
219 bouquet = self.servicelist.bouquet_root
221 serviceHandler = eServiceCenter.getInstance()
222 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
223 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
225 bouquetlist = serviceHandler.list(bouquet)
226 if not bouquetlist is None:
228 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
229 if not bouquet.valid(): #check end of list
231 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
233 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
234 if not service is None:
235 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
236 self.servicelist.clearPath()
237 if self.servicelist.bouquet_root != bouquet:
238 self.servicelist.enterPath(self.servicelist.bouquet_root)
239 self.servicelist.enterPath(bouquet)
240 self.servicelist.setCurrentSelection(service) #select the service in servicelist
241 self.servicelist.zap()
243 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
245 class InfoBarChannelSelection:
246 """ ChannelSelection - handles the channelSelection dialog and the initial
247 channelChange actions which open the channelSelection dialog """
250 self.servicelist = self.session.instantiateDialog(ChannelSelection)
252 if config.misc.initialchannelselection.value == 1:
253 self.onShown.append(self.firstRun)
255 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
257 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
258 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
259 "zapUp": (self.zapUp, _("previous channel")),
260 "zapDown": (self.zapDown, _("next channel")),
261 "historyBack": (self.historyBack, _("previous channel in history")),
262 "historyNext": (self.historyNext, _("next channel in history")),
263 "openServiceList": (self.openServiceList, _("open servicelist")),
266 def showTvChannelList(self, zap=False):
267 self.servicelist.setModeTv()
269 self.servicelist.zap()
270 self.session.execDialog(self.servicelist)
272 def showRadioChannelList(self, zap=False):
273 self.servicelist.setModeRadio()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
279 self.onShown.remove(self.firstRun)
280 config.misc.initialchannelselection.value = 0
281 config.misc.initialchannelselection.save()
282 self.switchChannelDown()
284 def historyBack(self):
285 self.servicelist.historyBack()
287 def historyNext(self):
288 self.servicelist.historyNext()
290 def switchChannelUp(self):
291 self.servicelist.moveUp()
292 self.session.execDialog(self.servicelist)
294 def switchChannelDown(self):
295 self.servicelist.moveDown()
296 self.session.execDialog(self.servicelist)
298 def openServiceList(self):
299 self.session.execDialog(self.servicelist)
302 if self.servicelist.inBouquet():
303 prev = self.servicelist.getCurrentSelection()
305 prev = prev.toString()
307 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
308 if self.servicelist.atBegin():
309 self.servicelist.prevBouquet()
310 self.servicelist.moveUp()
311 cur = self.servicelist.getCurrentSelection()
312 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
315 self.servicelist.moveUp()
316 self.servicelist.zap()
320 if self.servicelist.inBouquet():
321 prev = self.servicelist.getCurrentSelection()
323 prev = prev.toString()
325 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.atEnd():
326 self.servicelist.nextBouquet()
328 self.servicelist.moveDown()
329 cur = self.servicelist.getCurrentSelection()
330 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
333 self.servicelist.moveDown()
334 self.servicelist.zap()
338 """ Handles a menu action, to open the (main) menu """
340 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
342 "mainMenu": (self.mainMenu, _("Enter main menu...")),
346 print "loading mainmenu XML..."
347 menu = mdom.childNodes[0]
348 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
349 self.session.open(MainMenu, menu, menu.childNodes)
351 class InfoBarSimpleEventView:
352 """ Opens the Eventview for now/next """
354 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
356 "showEventInfo": (self.openEventView, _("show event details")),
359 def openEventView(self):
361 service = self.session.nav.getCurrentService()
362 ref = self.session.nav.getCurrentlyPlayingServiceReference()
363 info = service.info()
366 self.epglist.append(ptr)
369 self.epglist.append(ptr)
370 if len(self.epglist) > 0:
371 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
373 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
374 if len(self.epglist) > 1:
375 tmp = self.epglist[0]
376 self.epglist[0]=self.epglist[1]
378 setEvent(self.epglist[0])
381 """ EPG - Opens an EPG list when the showEPGList action fires """
383 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
385 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
388 self.is_now_next = False
390 self.bouquetSel = None
391 self.eventView = None
392 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
394 "showEventInfo": (self.openEventView, _("show EPG...")),
397 def zapToService(self, service):
398 if not service is None:
399 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
400 self.servicelist.clearPath()
401 if self.servicelist.bouquet_root != self.epg_bouquet:
402 self.servicelist.enterPath(self.servicelist.bouquet_root)
403 self.servicelist.enterPath(self.epg_bouquet)
404 self.servicelist.setCurrentSelection(service) #select the service in servicelist
405 self.servicelist.zap()
407 def getBouquetServices(self, bouquet):
409 servicelist = eServiceCenter.getInstance().list(bouquet)
410 if not servicelist is None:
412 service = servicelist.getNext()
413 if not service.valid(): #check if end of list
415 if service.flags: #ignore non playable services
417 services.append(ServiceReference(service))
420 def openBouquetEPG(self, bouquet, withCallback=True):
421 services = self.getBouquetServices(bouquet)
423 self.epg_bouquet = bouquet
425 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
427 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
429 def changeBouquetCB(self, direction, epg):
432 self.bouquetSel.down()
435 bouquet = self.bouquetSel.getCurrent()
436 services = self.getBouquetServices(bouquet)
438 self.epg_bouquet = bouquet
439 epg.setServices(services)
441 def closed(self, ret=False):
442 closedScreen = self.dlg_stack.pop()
443 if self.bouquetSel and closedScreen == self.bouquetSel:
444 self.bouquetSel = None
445 elif self.eventView and closedScreen == self.eventView:
446 self.eventView = None
448 dlgs=len(self.dlg_stack)
450 self.dlg_stack[dlgs-1].close(dlgs > 1)
452 def openMultiServiceEPG(self, withCallback=True):
453 bouquets = self.servicelist.getBouquetList()
458 if cnt > 1: # show bouquet list
460 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
461 self.dlg_stack.append(self.bouquetSel)
463 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
465 self.openBouquetEPG(bouquets[0][1], withCallback)
467 def openSingleServiceEPG(self):
468 ref=self.session.nav.getCurrentlyPlayingServiceReference()
469 self.session.open(EPGSelection, ref)
471 def openSimilarList(self, eventid, refstr):
472 self.session.open(EPGSelection, refstr, None, eventid)
474 def getNowNext(self):
476 service = self.session.nav.getCurrentService()
477 info = service and service.info()
478 ptr = info and info.getEvent(0)
480 self.epglist.append(ptr)
481 ptr = info and info.getEvent(1)
483 self.epglist.append(ptr)
485 def __evEventInfoChanged(self):
486 if self.is_now_next and len(self.dlg_stack) == 1:
488 assert self.eventView
489 if len(self.epglist):
490 self.eventView.setEvent(self.epglist[0])
492 def openEventView(self):
493 ref = self.session.nav.getCurrentlyPlayingServiceReference()
495 if len(self.epglist) == 0:
496 self.is_now_next = False
497 epg = eEPGCache.getInstance()
498 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
500 self.epglist.append(ptr)
501 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
503 self.epglist.append(ptr)
505 self.is_now_next = True
506 if len(self.epglist) > 0:
507 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
508 self.dlg_stack.append(self.eventView)
510 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
511 self.openMultiServiceEPG(False)
513 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
514 if len(self.epglist) > 1:
515 tmp = self.epglist[0]
516 self.epglist[0]=self.epglist[1]
518 setEvent(self.epglist[0])
521 """provides a snr/agc/ber display"""
523 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
526 """provides a current/next event info display"""
528 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
529 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
531 class InfoBarServiceName:
533 self["CurrentService"] = CurrentService(self.session.nav)
536 """handles actions like seeking, pause"""
538 # ispause, isff, issm
539 SEEK_STATE_PLAY = (0, 0, 0, ">")
540 SEEK_STATE_PAUSE = (1, 0, 0, "||")
541 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
542 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
543 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
544 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
545 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
546 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
548 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
549 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
550 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
551 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
553 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
554 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
555 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
558 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
560 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
561 iPlayableService.evStart: self.__serviceStarted,
563 iPlayableService.evEOF: self.__evEOF,
564 iPlayableService.evSOF: self.__evSOF,
567 class InfoBarSeekActionMap(HelpableActionMap):
568 def __init__(self, screen, *args, **kwargs):
569 HelpableActionMap.__init__(self, screen, *args, **kwargs)
572 def action(self, contexts, action):
573 if action[:5] == "seek:":
574 time = int(action[5:])
575 self.screen.seekRelative(time * 90000)
578 return HelpableActionMap.action(self, contexts, action)
580 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
582 "pauseService": (self.pauseService, _("pause")),
583 "unPauseService": (self.unPauseService, _("continue")),
585 "seekFwd": (self.seekFwd, _("skip forward")),
586 "seekFwdDown": self.seekFwdDown,
587 "seekFwdUp": self.seekFwdUp,
588 "seekBack": (self.seekBack, _("skip backward")),
589 "seekBackDown": self.seekBackDown,
590 "seekBackUp": self.seekBackUp,
592 # give them a little more priority to win over color buttons
594 self.seekstate = self.SEEK_STATE_PLAY
595 self.onClose.append(self.delTimer)
597 self.fwdtimer = False
598 self.fwdKeyTimer = eTimer()
599 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
601 self.rwdtimer = False
602 self.rwdKeyTimer = eTimer()
603 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
605 self.onPlayStateChanged = [ ]
607 self.lockedBecauseOfSkipping = False
620 service = self.session.nav.getCurrentService()
624 seek = service.seek()
626 if seek is None or not seek.isCurrentlySeekable():
631 def isSeekable(self):
632 if self.getSeek() is None:
636 def __seekableStatusChanged(self):
637 print "seekable status changed!"
638 if not self.isSeekable():
639 self["SeekActions"].setEnabled(False)
640 print "not seekable, return to play"
641 self.setSeekState(self.SEEK_STATE_PLAY)
643 self["SeekActions"].setEnabled(True)
646 def __serviceStarted(self):
647 self.seekstate = self.SEEK_STATE_PLAY
649 def setSeekState(self, state):
650 service = self.session.nav.getCurrentService()
655 if not self.isSeekable():
656 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
657 state = self.SEEK_STATE_PLAY
659 pauseable = service.pause()
661 if pauseable is None:
662 print "not pauseable."
663 state = self.SEEK_STATE_PLAY
665 oldstate = self.seekstate
666 self.seekstate = state
669 if oldstate[i] != self.seekstate[i]:
670 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
672 for c in self.onPlayStateChanged:
675 self.checkSkipShowHideLock()
679 def pauseService(self):
680 if self.seekstate == self.SEEK_STATE_PAUSE:
681 print "pause, but in fact unpause"
682 self.unPauseService()
684 if self.seekstate == self.SEEK_STATE_PLAY:
685 print "yes, playing."
687 print "no", self.seekstate
689 self.setSeekState(self.SEEK_STATE_PAUSE);
691 def unPauseService(self):
693 if self.seekstate == self.SEEK_STATE_PLAY:
695 self.setSeekState(self.SEEK_STATE_PLAY)
697 def doSeek(self, seektime):
698 print "doseek", seektime
699 service = self.session.nav.getCurrentService()
703 seekable = self.getSeek()
707 seekable.seekTo(90 * seektime)
709 def seekFwdDown(self):
710 print "start fwd timer"
712 self.fwdKeyTimer.start(1000)
714 def seekBackDown(self):
715 print "start rewind timer"
717 self.rwdKeyTimer.start(1000)
722 self.fwdKeyTimer.stop()
723 self.fwdtimer = False
728 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
729 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
730 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
731 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
732 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
733 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
734 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
735 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
736 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
737 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
738 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
739 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
740 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
741 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
742 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
744 self.setSeekState(lookup[self.seekstate])
746 def seekBackUp(self):
749 self.rwdKeyTimer.stop()
750 self.rwdtimer = False
755 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
756 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
757 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
758 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
759 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
760 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
761 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
762 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
763 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
764 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
765 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
766 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
767 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
768 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
769 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
771 self.setSeekState(lookup[self.seekstate])
773 if self.seekstate == self.SEEK_STATE_PAUSE:
774 seekable = self.getSeek()
775 if seekable is not None:
776 seekable.seekRelative(-1, 3)
778 def fwdTimerFire(self):
779 print "Display seek fwd"
780 self.fwdKeyTimer.stop()
781 self.fwdtimer = False
782 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
784 def fwdSeekTo(self, minutes):
785 print "Seek", minutes, "minutes forward"
787 seekable = self.getSeek()
788 if seekable is not None:
789 seekable.seekRelative(1, minutes * 60 * 90000)
791 def rwdTimerFire(self):
793 self.rwdKeyTimer.stop()
794 self.rwdtimer = False
795 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
797 def rwdSeekTo(self, minutes):
799 self.fwdSeekTo(0 - minutes)
801 def checkSkipShowHideLock(self):
802 wantlock = self.seekstate != self.SEEK_STATE_PLAY
804 if self.lockedBecauseOfSkipping and not wantlock:
806 self.lockedBecauseOfSkipping = False
808 if wantlock and not self.lockedBecauseOfSkipping:
810 self.lockedBecauseOfSkipping = True
813 if self.seekstate != self.SEEK_STATE_PLAY:
814 self.setSeekState(self.SEEK_STATE_PAUSE)
816 #self.getSeek().seekRelative(1, -90000)
817 self.setSeekState(self.SEEK_STATE_PLAY)
819 self.setSeekState(self.SEEK_STATE_PAUSE)
822 self.setSeekState(self.SEEK_STATE_PLAY)
825 def seekRelative(self, diff):
826 seekable = self.getSeek()
827 if seekable is not None:
828 seekable.seekRelative(1, diff)
830 from Screens.PVRState import PVRState, TimeshiftState
832 class InfoBarPVRState:
833 def __init__(self, screen=PVRState):
834 self.onPlayStateChanged.append(self.__playStateChanged)
835 self.pvrStateDialog = self.session.instantiateDialog(screen)
836 self.onShow.append(self.__mayShow)
837 self.onHide.append(self.pvrStateDialog.hide)
840 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
841 self.pvrStateDialog.show()
843 def __playStateChanged(self, state):
844 playstateString = state[3]
845 self.pvrStateDialog["state"].setText(playstateString)
848 class InfoBarTimeshiftState(InfoBarPVRState):
850 InfoBarPVRState.__init__(self, screen=TimeshiftState)
852 class InfoBarShowMovies:
854 # i don't really like this class.
855 # it calls a not further specified "movie list" on up/down/movieList,
856 # so this is not more than an action map
858 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
860 "movieList": (self.showMovies, "movie list"),
861 "up": (self.showMovies, "movie list"),
862 "down": (self.showMovies, "movie list")
865 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
869 # Timeshift works the following way:
870 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
871 # - normal playback TUNER unused PLAY enable disable disable
872 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
873 # - user presess pause again FILE record PLAY enable disable enable
874 # - user fast forwards FILE record FF enable disable enable
875 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
876 # - user backwards FILE record BACK # !! enable disable enable
880 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
881 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
882 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
883 # - the user can now PVR around
884 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
885 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
887 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
888 # - if the user rewinds, or press pause, timeshift will be activated again
890 # note that a timeshift can be enabled ("recording") and
891 # activated (currently time-shifting).
893 class InfoBarTimeshift:
895 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
897 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
898 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
900 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
902 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
903 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
904 }, prio=-1) # priority over record
906 self.timeshift_enabled = 0
907 self.timeshift_state = 0
908 self.ts_pause_timer = eTimer()
909 self.ts_pause_timer.timeout.get().append(self.pauseService)
911 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
913 iPlayableService.evStart: self.__serviceStarted,
914 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
917 def getTimeshift(self):
918 service = self.session.nav.getCurrentService()
919 return service and service.timeshift()
921 def startTimeshift(self):
922 print "enable timeshift"
923 ts = self.getTimeshift()
925 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
926 # print "no ts interface"
929 if self.timeshift_enabled:
930 print "hu, timeshift already enabled?"
932 if not ts.startTimeshift():
934 self.timeshift_enabled = 1
936 # we remove the "relative time" for now.
937 #self.pvrStateDialog["timeshift"].setRelative(time.time())
940 self.setSeekState(self.SEEK_STATE_PAUSE)
942 # enable the "TimeshiftEnableActions", which will override
943 # the startTimeshift actions
944 self.__seekableStatusChanged()
946 print "timeshift failed"
948 def stopTimeshift(self):
949 if not self.timeshift_enabled:
951 print "disable timeshift"
952 ts = self.getTimeshift()
955 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
957 def stopTimeshiftConfirmed(self, confirmed):
961 ts = self.getTimeshift()
966 self.timeshift_enabled = 0
969 self.__seekableStatusChanged()
971 # activates timeshift, and seeks to (almost) the end
972 def activateTimeshiftEnd(self):
973 ts = self.getTimeshift()
978 if ts.isTimeshiftActive():
979 print "!! activate timeshift called - but shouldn't this be a normal pause?"
982 self.setSeekState(self.SEEK_STATE_PLAY)
983 ts.activateTimeshift()
986 # same as activateTimeshiftEnd, but pauses afterwards.
987 def activateTimeshiftEndAndPause(self):
988 state = self.seekstate
989 self.activateTimeshiftEnd()
991 # well, this is "andPause", but it could be pressed from pause,
992 # when pausing on the (fake-)"live" picture, so an un-pause
995 print "now, pauseService"
996 if state == self.SEEK_STATE_PLAY:
997 print "is PLAYING, start pause timer"
998 self.ts_pause_timer.start(200, 1)
1001 self.unPauseService()
1003 def __seekableStatusChanged(self):
1006 print "self.isSeekable", self.isSeekable()
1007 print "self.timeshift_enabled", self.timeshift_enabled
1009 # when this service is not seekable, but timeshift
1010 # is enabled, this means we can activate
1012 if not self.isSeekable() and self.timeshift_enabled:
1015 print "timeshift activate:", enabled
1016 self["TimeshiftActivateActions"].setEnabled(enabled)
1018 def __serviceStarted(self):
1019 self.timeshift_enabled = False
1020 self.__seekableStatusChanged()
1022 from Screens.PiPSetup import PiPSetup
1024 class InfoBarExtensions:
1025 EXTENSION_SINGLE = 0
1031 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1033 "extensions": (self.showExtensionSelection, _("view extensions...")),
1036 def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1037 self.list.append((type, extension, key))
1039 def updateExtension(self, extension, key = None):
1040 self.extensionsList.append(extension)
1042 if self.extensionKeys.has_key(key):
1046 for x in self.availableKeys:
1047 if not self.extensionKeys.has_key(x):
1052 self.extensionKeys[key] = len(self.extensionsList) - 1
1054 def updateExtensions(self):
1055 self.extensionsList = []
1056 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1057 self.extensionKeys = {}
1059 if x[0] == self.EXTENSION_SINGLE:
1060 self.updateExtension(x[1], x[2])
1063 self.updateExtension(y[0], y[1])
1066 def showExtensionSelection(self):
1067 self.updateExtensions()
1068 extensionsList = self.extensionsList[:]
1071 for x in self.availableKeys:
1072 if self.extensionKeys.has_key(x):
1073 entry = self.extensionKeys[x]
1074 extension = self.extensionsList[entry]
1076 name = str(extension[0]())
1077 list.append((extension[0](), extension))
1079 extensionsList.remove(extension)
1081 extensionsList.remove(extension)
1082 for x in extensionsList:
1083 list.append((x[0](), x))
1084 keys += [""] * len(extensionsList)
1085 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1087 def extensionCallback(self, answer):
1088 if answer is not None:
1091 from Tools.BoundFunction import boundFunction
1093 # depends on InfoBarExtensions and InfoBarSubtitleSupport
1094 class InfoBarSubtitles:
1096 self.addExtension((self.getDisableSubtitleName, self.disableSubtitles, self.subtitlesEnabled), "4")
1097 self.addExtension(extension = self.getSubtitleList, type = InfoBarExtensions.EXTENSION_LIST)
1099 def getDisableSubtitleName(self):
1100 return _("Disable subtitles")
1102 def getSubtitleList(self):
1104 s = self.getCurrentServiceSubtitle()
1105 l = s and s.getSubtitleList() or [ ]
1108 list.append(((boundFunction(self.getSubtitleEntryName, x[0]), boundFunction(self.enableSubtitle, x[1]), lambda: True), None))
1111 def getSubtitleEntryName(self, name):
1112 return "Enable Subtitles: " + name
1114 def enableSubtitle(self, subtitles):
1115 print "enable subitles", subtitles
1116 self.selected_subtitle = subtitles
1117 self.subtitles_enabled = True
1119 def subtitlesEnabled(self):
1120 return self.subtitles_enabled
1122 def disableSubtitles(self):
1123 self.subtitles_enabled = False
1125 # depends on InfoBarExtensions
1128 self.session.pipshown = False
1130 self.addExtension((self.getShowHideName, self.showPiP, self.available), "1")
1131 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "2")
1132 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "3")
1135 def available(self):
1139 return self.session.pipshown
1141 def getShowHideName(self):
1142 if self.session.pipshown:
1143 return _("Disable Picture in Picture")
1145 return _("Activate Picture in Picture")
1147 def getSwapName(self):
1148 return _("Swap Services")
1150 def getMoveName(self):
1151 return _("Move Picture in Picture")
1154 if self.session.pipshown:
1155 del self.session.pip
1156 self.session.pipshown = False
1158 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1159 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1160 if self.session.pip.playService(newservice):
1161 self.session.pipshown = True
1162 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1164 self.session.pipshown = False
1165 del self.session.pip
1166 self.session.nav.playService(newservice)
1169 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1170 if self.session.pip.servicePath:
1171 servicepath = self.servicelist.getCurrentServicePath()
1172 ref=servicepath[len(servicepath)-1]
1173 pipref=self.session.pip.getCurrentService()
1174 self.session.pip.playService(swapservice)
1175 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1176 if pipref.toString() != ref.toString(): # is a subservice ?
1177 self.session.nav.stopService() # stop portal
1178 self.session.nav.playService(pipref) # start subservice
1179 self.session.pip.servicePath=servicepath
1182 self.session.open(PiPSetup, pip = self.session.pip)
1184 from RecordTimer import parseEvent
1186 class InfoBarInstantRecord:
1187 """Instant Record - handles the instantRecord action in order to
1188 start/stop instant records"""
1190 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1192 "instantRecord": (self.instantRecord, _("Instant Record...")),
1195 self["BlinkingPoint"] = BlinkingPixmapConditional()
1196 self["BlinkingPoint"].hide()
1197 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1199 def stopCurrentRecording(self, entry = -1):
1200 if entry is not None and entry != -1:
1201 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1202 self.recording.remove(self.recording[entry])
1204 def startInstantRecording(self, limitEvent = False):
1205 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1207 # try to get event info
1210 service = self.session.nav.getCurrentService()
1211 epg = eEPGCache.getInstance()
1212 event = epg.lookupEventTime(serviceref, -1, 0)
1214 info = service.info()
1215 ev = info.getEvent(0)
1221 end = time.time() + 3600 * 10
1222 name = "instant record"
1226 if event is not None:
1227 curEvent = parseEvent(event)
1229 description = curEvent[3]
1230 eventid = curEvent[4]
1235 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1237 data = (begin, end, name, description, eventid)
1239 recording = self.session.nav.recordWithTimer(serviceref, *data)
1240 recording.dontSave = True
1241 self.recording.append(recording)
1243 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1245 def isInstantRecordRunning(self):
1246 print "self.recording:", self.recording
1247 if len(self.recording) > 0:
1248 for x in self.recording:
1253 def recordQuestionCallback(self, answer):
1254 print "pre:\n", self.recording
1256 if answer is None or answer[1] == "no":
1259 recording = self.recording[:]
1261 if not x in self.session.nav.RecordTimer.timer_list:
1262 self.recording.remove(x)
1263 elif x.dontSave and x.isRunning():
1264 list.append(TimerEntryComponent(x, False))
1266 if answer[1] == "changeduration":
1267 if len(self.recording) == 1:
1268 self.changeDuration(0)
1270 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1271 elif answer[1] == "stop":
1272 if len(self.recording) == 1:
1273 self.stopCurrentRecording(0)
1275 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1276 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1278 if answer[1] == "event":
1280 if answer[1] == "manualduration":
1281 self.selectedEntry = len(self.recording)
1282 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1283 self.startInstantRecording(limitEvent = limitEvent)
1285 print "after:\n", self.recording
1287 def changeDuration(self, entry):
1288 if entry is not None:
1289 self.selectedEntry = entry
1290 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1292 def inputCallback(self, value):
1293 if value is not None:
1294 print "stopping recording after", int(value), "minutes."
1295 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1296 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1298 def instantRecord(self):
1300 stat = os.stat(resolveFilename(SCOPE_HDD))
1302 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1305 if self.isInstantRecordRunning():
1306 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")])
1308 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")])
1310 from Tools.ISO639 import LanguageCodes
1312 class InfoBarAudioSelection:
1314 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1316 "audioSelection": (self.audioSelection, _("Audio Options...")),
1319 def audioSelection(self):
1320 service = self.session.nav.getCurrentService()
1321 audio = service and service.audioTracks()
1322 self.audioTracks = audio
1323 n = audio and audio.getNumberOfTracks() or 0
1324 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1326 print "tlist:", tlist
1328 self.audioChannel = service.audioChannel()
1331 i = audio.getTrackInfo(x)
1332 language = i.getLanguage()
1333 description = i.getDescription()
1335 if len(language) == 3:
1336 if language in LanguageCodes:
1337 language = LanguageCodes[language][0]
1339 if len(description):
1340 description += " (" + language + ")"
1342 description = language
1344 tlist.append((description, x))
1346 selectedAudio = tlist[0][1]
1347 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1351 if x[1] != selectedAudio:
1356 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1357 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1359 del self.audioTracks
1361 def audioSelected(self, audio):
1362 if audio is not None:
1363 if isinstance(audio[1], str):
1364 if audio[1] == "mode":
1365 keys = ["red", "green", "yellow"]
1366 selection = self.audioChannel.getCurrentChannel()
1367 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1368 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1370 del self.audioChannel
1371 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1372 self.audioTracks.selectTrack(audio[1])
1374 del self.audioChannel
1375 del self.audioTracks
1377 def modeSelected(self, mode):
1378 if mode is not None:
1379 self.audioChannel.selectChannel(mode[1])
1380 del self.audioChannel
1383 class InfoBarSubserviceSelection:
1385 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1387 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1390 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1392 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1393 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1395 self["SubserviceQuickzapAction"].setEnabled(False)
1397 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1399 def checkSubservicesAvail(self, ev):
1400 if ev == iPlayableService.evUpdatedEventInfo:
1401 service = self.session.nav.getCurrentService()
1402 subservices = service and service.subServices()
1403 if not subservices or subservices.getNumberOfSubservices() == 0:
1404 self["SubserviceQuickzapAction"].setEnabled(False)
1406 def nextSubservice(self):
1407 self.changeSubservice(+1)
1409 def prevSubservice(self):
1410 self.changeSubservice(-1)
1412 def changeSubservice(self, direction):
1413 service = self.session.nav.getCurrentService()
1414 subservices = service and service.subServices()
1415 n = subservices and subservices.getNumberOfSubservices()
1418 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1420 if subservices.getSubservice(x).toString() == ref.toString():
1423 selection += direction
1428 newservice = subservices.getSubservice(selection)
1429 if newservice.valid():
1432 self.session.nav.playService(newservice)
1434 def subserviceSelection(self):
1435 service = self.session.nav.getCurrentService()
1436 subservices = service and service.subServices()
1438 n = subservices and subservices.getNumberOfSubservices()
1441 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1444 i = subservices.getSubservice(x)
1445 if i.toString() == ref.toString():
1447 tlist.append((i.getName(), i))
1449 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1451 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1453 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1455 def subserviceSelected(self, service):
1456 if not service is None:
1457 if isinstance(service[1], str):
1458 if service[1] == "quickzap":
1459 from Screens.SubservicesQuickzap import SubservicesQuickzap
1460 self.session.open(SubservicesQuickzap, service[2])
1462 self["SubserviceQuickzapAction"].setEnabled(True)
1463 self.session.nav.playService(service[1])
1465 class InfoBarAdditionalInfo:
1467 self["NimA"] = Pixmap()
1468 self["NimB"] = Pixmap()
1469 self["NimA_Active"] = Pixmap()
1470 self["NimB_Active"] = Pixmap()
1472 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1473 self["TimeshiftPossible"] = self["RecordingPossible"]
1474 self["ExtensionsAvailable"] = Boolean(fixed=1)
1476 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1477 res_mgr = eDVBResourceManagerPtr()
1478 if eDVBResourceManager.getInstance(res_mgr) == 0:
1479 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1481 def tunerUseMaskChanged(self, mask):
1483 self["NimA_Active"].show()
1485 self["NimA_Active"].hide()
1487 self["NimB_Active"].show()
1489 self["NimB_Active"].hide()
1491 def checkTunerState(self, service):
1492 info = service.frontendInfo()
1493 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1494 if feNumber is None:
1504 def gotServiceEvent(self, ev):
1505 service = self.session.nav.getCurrentService()
1506 if ev == iPlayableService.evStart:
1507 self.checkTunerState(service)
1509 class InfoBarNotifications:
1511 self.onExecBegin.append(self.checkNotifications)
1512 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1513 self.onClose.append(self.__removeNotification)
1515 def __removeNotification(self):
1516 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1518 def checkNotificationsIfExecing(self):
1520 self.checkNotifications()
1522 def checkNotifications(self):
1523 if len(Notifications.notifications):
1524 n = Notifications.notifications[0]
1525 Notifications.notifications = Notifications.notifications[1:]
1528 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1530 self.session.open(n[1], *n[2], **n[3])
1532 class InfoBarServiceNotifications:
1534 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1536 iPlayableService.evEnd: self.serviceHasEnded
1539 def serviceHasEnded(self):
1540 print "service end!"
1543 self.setSeekState(self.SEEK_STATE_PLAY)
1547 class InfoBarCueSheetSupport:
1553 ENABLE_RESUME_SUPPORT = False
1556 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1558 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1559 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1560 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1564 self.is_closing = False
1565 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1567 iPlayableService.evStart: self.__serviceStarted,
1570 def __serviceStarted(self):
1573 print "new service started! trying to download cuts!"
1574 self.downloadCuesheet()
1576 if self.ENABLE_RESUME_SUPPORT:
1579 for (pts, what) in self.cut_list:
1580 if what == self.CUT_TYPE_LAST:
1583 if last is not None:
1584 self.resume_point = last
1585 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1587 def playLastCB(self, answer):
1589 seekable = self.__getSeekable()
1590 if seekable is not None:
1591 seekable.seekTo(self.resume_point)
1593 def __getSeekable(self):
1594 service = self.session.nav.getCurrentService()
1597 return service.seek()
1599 def cueGetCurrentPosition(self):
1600 seek = self.__getSeekable()
1603 r = seek.getPlayPosition()
1608 def jumpPreviousNextMark(self, cmp, alternative=None):
1609 current_pos = self.cueGetCurrentPosition()
1610 if current_pos is None:
1612 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1613 if mark is not None:
1615 elif alternative is not None:
1620 seekable = self.__getSeekable()
1621 if seekable is not None:
1622 seekable.seekTo(pts)
1624 def jumpPreviousMark(self):
1625 # we add 2 seconds, so if the play position is <2s after
1626 # the mark, the mark before will be used
1627 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1629 def jumpNextMark(self):
1630 self.jumpPreviousNextMark(lambda x: x)
1632 def getNearestCutPoint(self, pts, cmp=abs):
1635 for cp in self.cut_list:
1636 diff = cmp(cp[0] - pts)
1637 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1641 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1642 current_pos = self.cueGetCurrentPosition()
1643 if current_pos is None:
1644 print "not seekable"
1647 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1649 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1651 return nearest_cutpoint
1653 self.removeMark(nearest_cutpoint)
1654 elif not onlyremove and not onlyreturn:
1655 self.addMark((current_pos, self.CUT_TYPE_MARK))
1660 def addMark(self, point):
1661 bisect.insort(self.cut_list, point)
1662 self.uploadCuesheet()
1664 def removeMark(self, point):
1665 self.cut_list.remove(point)
1666 self.uploadCuesheet()
1668 def __getCuesheet(self):
1669 service = self.session.nav.getCurrentService()
1672 return service.cueSheet()
1674 def uploadCuesheet(self):
1675 cue = self.__getCuesheet()
1678 print "upload failed, no cuesheet interface"
1680 cue.setCutList(self.cut_list)
1682 def downloadCuesheet(self):
1683 cue = self.__getCuesheet()
1686 print "upload failed, no cuesheet interface"
1688 self.cut_list = cue.getCutList()
1690 class InfoBarSummary(Screen):
1692 <screen position="0,0" size="132,64">
1693 <widget source="CurrentTime" render="Label" position="50,46" size="82,18" font="Regular;16" >
1694 <convert type="ClockToText">WithSeconds</convert>
1696 <widget source="CurrentService" render="Label" position="0,4" size="132,42" font="Regular;18" >
1697 <convert type="ServiceName">Name</convert>
1701 def __init__(self, session, parent):
1702 Screen.__init__(self, session)
1703 self["CurrentService"] = CurrentService(self.session.nav)
1704 self["CurrentTime"] = Clock()
1706 class InfoBarSummarySupport:
1710 def createSummary(self):
1711 return InfoBarSummary
1713 class InfoBarTeletextPlugin:
1715 self.teletext_plugin = None
1717 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1718 self.teletext_plugin = p
1720 if self.teletext_plugin is not None:
1721 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1723 "startTeletext": (self.startTeletext, _("View teletext..."))
1726 print "no teletext plugin found!"
1728 def startTeletext(self):
1729 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1731 class InfoBarSubtitleSupport(object):
1733 object.__init__(self)
1734 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1735 self.__subtitles_enabled = False
1737 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1739 iPlayableService.evStart: self.__serviceStarted,
1742 def __serviceStarted(self):
1743 # reenable if it was enabled
1744 r = self.__subtitles_enabled
1745 self.__subtitles_enabled = False
1746 self.__selected_subtitle = None
1747 self.setSubtitlesEnable(r)
1749 def getCurrentServiceSubtitle(self):
1750 service = self.session.nav.getCurrentService()
1751 return service and service.subtitle()
1753 def setSubtitlesEnable(self, enable=True):
1754 subtitle = self.getCurrentServiceSubtitle()
1755 if enable and self.__selected_subtitle:
1756 if subtitle and not self.__subtitles_enabled:
1757 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1758 self.subtitle_window.show()
1759 self.__subtitles_enabled = True
1762 subtitle.disableSubtitles(self.subtitle_window.instance)
1764 self.subtitle_window.hide()
1765 self.__subtitles_enabled = False
1767 def setSelectedSubtitle(self, subtitle):
1768 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1770 self.__selected_subtitle = subtitle
1771 self.__serviceStarted()
1773 self.__selected_subtitle = subtitle
1775 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1776 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)