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:
1026 self.session.pipshown = False
1028 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1030 "extensions": (self.extensions, _("view extensions...")),
1039 def extensions(self):
1041 if self.session.pipshown == False:
1042 list.append((_("Activate Picture in Picture"), self.PIPON))
1043 elif self.session.pipshown == True:
1044 list.append((_("Disable Picture in Picture"), self.PIPOFF))
1045 list.append((_("Move Picture in Picture"), self.MOVEPIP))
1046 list.append((_("Swap services"), self.PIPSWAP))
1048 s = self.getCurrentServiceSubtitle()
1049 l = s and s.getSubtitleList() or [ ]
1052 list.append(("Enable Subtitles: " + x[0], self.ENABLE_SUBTITLE, x[1]))
1054 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
1056 def extensionCallback(self, answer):
1057 if answer is not None:
1058 if answer[1] == self.PIPON:
1059 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1060 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1061 if self.session.pip.playService(newservice):
1062 self.session.pipshown = True
1063 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1065 self.session.pipshown = False
1066 del self.session.pip
1067 self.session.nav.playService(newservice)
1068 elif answer[1] == self.PIPOFF:
1069 del self.session.pip
1070 self.session.pipshown = False
1071 elif answer[1] == self.PIPSWAP:
1072 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1073 if self.session.pip.servicePath:
1074 servicepath = self.servicelist.getCurrentServicePath()
1075 ref=servicepath[len(servicepath)-1]
1076 pipref=self.session.pip.getCurrentService()
1077 self.session.pip.playService(swapservice)
1078 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1079 if pipref.toString() != ref.toString(): # is a subservice ?
1080 self.session.nav.stopService() # stop portal
1081 self.session.nav.playService(pipref) # start subservice
1082 self.session.pip.servicePath=servicepath
1083 elif answer[1] == self.MOVEPIP:
1084 self.session.open(PiPSetup, pip = self.session.pip)
1085 elif answer[1] == self.ENABLE_SUBTITLE:
1086 self.selected_subtitle = answer[2]
1087 self.subtitles_enabled = True
1089 from RecordTimer import parseEvent
1091 class InfoBarInstantRecord:
1092 """Instant Record - handles the instantRecord action in order to
1093 start/stop instant records"""
1095 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1097 "instantRecord": (self.instantRecord, _("Instant Record...")),
1100 self["BlinkingPoint"] = BlinkingPixmapConditional()
1101 self["BlinkingPoint"].hide()
1102 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1104 def stopCurrentRecording(self, entry = -1):
1105 if entry is not None and entry != -1:
1106 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1107 self.recording.remove(self.recording[entry])
1109 def startInstantRecording(self, limitEvent = False):
1110 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1112 # try to get event info
1115 service = self.session.nav.getCurrentService()
1116 epg = eEPGCache.getInstance()
1117 event = epg.lookupEventTime(serviceref, -1, 0)
1119 info = service.info()
1120 ev = info.getEvent(0)
1126 end = time.time() + 3600 * 10
1127 name = "instant record"
1131 if event is not None:
1132 curEvent = parseEvent(event)
1134 description = curEvent[3]
1135 eventid = curEvent[4]
1140 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1142 data = (begin, end, name, description, eventid)
1144 recording = self.session.nav.recordWithTimer(serviceref, *data)
1145 recording.dontSave = True
1146 self.recording.append(recording)
1148 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1150 def isInstantRecordRunning(self):
1151 print "self.recording:", self.recording
1152 if len(self.recording) > 0:
1153 for x in self.recording:
1158 def recordQuestionCallback(self, answer):
1159 print "pre:\n", self.recording
1161 if answer is None or answer[1] == "no":
1164 recording = self.recording[:]
1166 if not x in self.session.nav.RecordTimer.timer_list:
1167 self.recording.remove(x)
1168 elif x.dontSave and x.isRunning():
1169 list.append(TimerEntryComponent(x, False))
1171 if answer[1] == "changeduration":
1172 if len(self.recording) == 1:
1173 self.changeDuration(0)
1175 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1176 elif answer[1] == "stop":
1177 if len(self.recording) == 1:
1178 self.stopCurrentRecording(0)
1180 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1181 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1183 if answer[1] == "event":
1185 if answer[1] == "manualduration":
1186 self.selectedEntry = len(self.recording)
1187 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1188 self.startInstantRecording(limitEvent = limitEvent)
1190 print "after:\n", self.recording
1192 def changeDuration(self, entry):
1193 if entry is not None:
1194 self.selectedEntry = entry
1195 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1197 def inputCallback(self, value):
1198 if value is not None:
1199 print "stopping recording after", int(value), "minutes."
1200 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1201 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1203 def instantRecord(self):
1205 stat = os.stat(resolveFilename(SCOPE_HDD))
1207 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1210 if self.isInstantRecordRunning():
1211 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")])
1213 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")])
1215 from Tools.ISO639 import LanguageCodes
1217 class InfoBarAudioSelection:
1219 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1221 "audioSelection": (self.audioSelection, _("Audio Options...")),
1224 def audioSelection(self):
1225 service = self.session.nav.getCurrentService()
1226 audio = service and service.audioTracks()
1227 self.audioTracks = audio
1228 n = audio and audio.getNumberOfTracks()
1229 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1231 print "tlist:", tlist
1233 self.audioChannel = service.audioChannel()
1236 i = audio.getTrackInfo(x)
1237 language = i.getLanguage()
1238 description = i.getDescription()
1240 if len(language) == 3:
1241 if language in LanguageCodes:
1242 language = LanguageCodes[language][0]
1244 if len(description):
1245 description += " (" + language + ")"
1247 description = language
1249 tlist.append((description, x))
1251 selectedAudio = tlist[0][1]
1252 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1256 if x[1] != selectedAudio:
1261 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1262 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1264 del self.audioTracks
1266 def audioSelected(self, audio):
1267 if audio is not None:
1268 if isinstance(audio[1], str):
1269 if audio[1] == "mode":
1270 keys = ["red", "green", "yellow"]
1271 selection = self.audioChannel.getCurrentChannel()
1272 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1273 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1275 del self.audioChannel
1276 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1277 self.audioTracks.selectTrack(audio[1])
1279 del self.audioChannel
1280 del self.audioTracks
1282 def modeSelected(self, mode):
1283 if mode is not None:
1284 self.audioChannel.selectChannel(mode[1])
1285 del self.audioChannel
1287 class InfoBarSubserviceSelection:
1289 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1291 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1294 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1296 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1297 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1299 self["SubserviceQuickzapAction"].setEnabled(False)
1301 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1303 def checkSubservicesAvail(self, ev):
1304 if ev == iPlayableService.evUpdatedEventInfo:
1305 service = self.session.nav.getCurrentService()
1306 subservices = service and service.subServices()
1307 if not subservices or subservices.getNumberOfSubservices() == 0:
1308 self["SubserviceQuickzapAction"].setEnabled(False)
1310 def nextSubservice(self):
1311 self.changeSubservice(+1)
1313 def prevSubservice(self):
1314 self.changeSubservice(-1)
1316 def changeSubservice(self, direction):
1317 service = self.session.nav.getCurrentService()
1318 subservices = service and service.subServices()
1319 n = subservices and subservices.getNumberOfSubservices()
1322 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1324 if subservices.getSubservice(x).toString() == ref.toString():
1327 selection += direction
1332 newservice = subservices.getSubservice(selection)
1333 if newservice.valid():
1336 self.session.nav.playService(newservice)
1338 def subserviceSelection(self):
1339 service = self.session.nav.getCurrentService()
1340 subservices = service and service.subServices()
1342 n = subservices and subservices.getNumberOfSubservices()
1345 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1348 i = subservices.getSubservice(x)
1349 if i.toString() == ref.toString():
1351 tlist.append((i.getName(), i))
1353 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection)
1355 def subserviceSelected(self, service):
1356 if not service is None:
1357 self["SubserviceQuickzapAction"].setEnabled(True)
1358 self.session.nav.playService(service[1])
1360 class InfoBarAdditionalInfo:
1362 self["NimA"] = Pixmap()
1363 self["NimB"] = Pixmap()
1364 self["NimA_Active"] = Pixmap()
1365 self["NimB_Active"] = Pixmap()
1367 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1368 self["TimeshiftPossible"] = self["RecordingPossible"]
1369 self["ExtensionsAvailable"] = Boolean(fixed=1)
1371 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1372 res_mgr = eDVBResourceManagerPtr()
1373 if eDVBResourceManager.getInstance(res_mgr) == 0:
1374 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1376 def tunerUseMaskChanged(self, mask):
1378 self["NimA_Active"].show()
1380 self["NimA_Active"].hide()
1382 self["NimB_Active"].show()
1384 self["NimB_Active"].hide()
1386 def checkTunerState(self, service):
1387 info = service.frontendInfo()
1388 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1389 if feNumber is None:
1399 def gotServiceEvent(self, ev):
1400 service = self.session.nav.getCurrentService()
1401 if ev == iPlayableService.evStart:
1402 self.checkTunerState(service)
1404 class InfoBarNotifications:
1406 self.onExecBegin.append(self.checkNotifications)
1407 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1408 self.onClose.append(self.__removeNotification)
1410 def __removeNotification(self):
1411 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1413 def checkNotificationsIfExecing(self):
1415 self.checkNotifications()
1417 def checkNotifications(self):
1418 if len(Notifications.notifications):
1419 n = Notifications.notifications[0]
1420 Notifications.notifications = Notifications.notifications[1:]
1423 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1425 self.session.open(n[1], *n[2], **n[3])
1427 class InfoBarServiceNotifications:
1429 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1431 iPlayableService.evEnd: self.serviceHasEnded
1434 def serviceHasEnded(self):
1435 print "service end!"
1438 self.setSeekState(self.SEEK_STATE_PLAY)
1442 class InfoBarCueSheetSupport:
1448 ENABLE_RESUME_SUPPORT = False
1451 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1453 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1454 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1455 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1459 self.is_closing = False
1460 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1462 iPlayableService.evStart: self.__serviceStarted,
1465 def __serviceStarted(self):
1468 print "new service started! trying to download cuts!"
1469 self.downloadCuesheet()
1471 if self.ENABLE_RESUME_SUPPORT:
1474 for (pts, what) in self.cut_list:
1475 if what == self.CUT_TYPE_LAST:
1478 if last is not None:
1479 self.resume_point = last
1480 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1482 def playLastCB(self, answer):
1484 seekable = self.__getSeekable()
1485 if seekable is not None:
1486 seekable.seekTo(self.resume_point)
1488 def __getSeekable(self):
1489 service = self.session.nav.getCurrentService()
1492 return service.seek()
1494 def cueGetCurrentPosition(self):
1495 seek = self.__getSeekable()
1498 r = seek.getPlayPosition()
1503 def jumpPreviousNextMark(self, cmp, alternative=None):
1504 current_pos = self.cueGetCurrentPosition()
1505 if current_pos is None:
1507 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1508 if mark is not None:
1510 elif alternative is not None:
1515 seekable = self.__getSeekable()
1516 if seekable is not None:
1517 seekable.seekTo(pts)
1519 def jumpPreviousMark(self):
1520 # we add 2 seconds, so if the play position is <2s after
1521 # the mark, the mark before will be used
1522 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1524 def jumpNextMark(self):
1525 self.jumpPreviousNextMark(lambda x: x)
1527 def getNearestCutPoint(self, pts, cmp=abs):
1530 for cp in self.cut_list:
1531 diff = cmp(cp[0] - pts)
1532 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1536 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1537 current_pos = self.cueGetCurrentPosition()
1538 if current_pos is None:
1539 print "not seekable"
1542 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1544 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1546 return nearest_cutpoint
1548 self.removeMark(nearest_cutpoint)
1549 elif not onlyremove and not onlyreturn:
1550 self.addMark((current_pos, self.CUT_TYPE_MARK))
1555 def addMark(self, point):
1556 bisect.insort(self.cut_list, point)
1557 self.uploadCuesheet()
1559 def removeMark(self, point):
1560 self.cut_list.remove(point)
1561 self.uploadCuesheet()
1563 def __getCuesheet(self):
1564 service = self.session.nav.getCurrentService()
1567 return service.cueSheet()
1569 def uploadCuesheet(self):
1570 cue = self.__getCuesheet()
1573 print "upload failed, no cuesheet interface"
1575 cue.setCutList(self.cut_list)
1577 def downloadCuesheet(self):
1578 cue = self.__getCuesheet()
1581 print "upload failed, no cuesheet interface"
1583 self.cut_list = cue.getCutList()
1585 class InfoBarSummary(Screen):
1587 <screen position="0,0" size="132,64">
1588 <widget source="CurrentTime" render="Label" position="50,46" size="82,18" font="Regular;16" >
1589 <convert type="ClockToText">WithSeconds</convert>
1591 <widget source="CurrentService" render="Label" position="0,4" size="132,42" font="Regular;18" >
1592 <convert type="ServiceName">Name</convert>
1596 def __init__(self, session, parent):
1597 Screen.__init__(self, session)
1598 self["CurrentService"] = CurrentService(self.session.nav)
1599 self["CurrentTime"] = Clock()
1601 class InfoBarSummarySupport:
1605 def createSummary(self):
1606 return InfoBarSummary
1608 class InfoBarTeletextPlugin:
1610 self.teletext_plugin = None
1612 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1613 self.teletext_plugin = p
1615 if self.teletext_plugin is not None:
1616 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1618 "startTeletext": (self.startTeletext, _("View teletext..."))
1621 print "no teletext plugin found!"
1623 def startTeletext(self):
1624 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1626 class InfoBarSubtitleSupport(object):
1628 object.__init__(self)
1629 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1630 self.__subtitles_enabled = False
1632 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1634 iPlayableService.evStart: self.__serviceStarted,
1637 def __serviceStarted(self):
1638 # reenable if it was enabled
1639 r = self.__subtitles_enabled
1640 self.__subtitles_enabled = False
1641 self.__selected_subtitle = None
1642 self.setSubtitlesEnable(r)
1644 def getCurrentServiceSubtitle(self):
1645 service = self.session.nav.getCurrentService()
1646 return service and service.subtitle()
1648 def setSubtitlesEnable(self, enable=True):
1649 subtitle = self.getCurrentServiceSubtitle()
1650 if enable and self.__selected_subtitle:
1651 if subtitle and not self.__subtitles_enabled:
1652 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1653 self.subtitle_window.show()
1654 self.__subtitles_enabled = True
1657 subtitle.disableSubtitles(self.subtitle_window.instance)
1659 self.subtitle_window.hide()
1660 self.__subtitles_enabled = False
1662 def setSelectedSubtitle(self, subtitle):
1663 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1665 self.__selected_subtitle = subtitle
1666 self.__serviceStarted()
1668 self.__selected_subtitle = subtitle
1670 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1671 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)