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.Clock import Clock
7 from Components.EventInfo import EventInfo, EventInfoProgress
8 from Components.Harddisk import harddiskmanager
9 from Components.Input import Input
10 from Components.Label import *
11 from Components.Pixmap import Pixmap, PixmapConditional
12 from Components.PluginComponent import plugins
13 from Components.ProgressBar import *
14 from Components.ServiceEventTracker import ServiceEventTracker
15 from Components.ServiceName import ServiceName
16 from Components.config import config, configElement, ConfigSubsection, configSequence, configElementBoolean, configSelection, configElement_nonSave, getConfigListEntry
17 from Components.config import configfile, configsequencearg
18 from Components.TimerList import TimerEntryComponent
19 from Components.TunerInfo import TunerInfo
21 from EpgSelection import EPGSelection
22 from Plugins.Plugin import PluginDescriptor
24 from Screen import Screen
25 from Screens.ChoiceBox import ChoiceBox
26 from Screens.Dish import Dish
27 from Screens.EventView import EventViewEPGSelect, EventViewSimple
28 from Screens.InputBox import InputBox
29 from Screens.MessageBox import MessageBox
30 from Screens.MinuteInput import MinuteInput
31 from Screens.TimerSelection import TimerSelection
32 from Screens.PictureInPicture import PictureInPicture
33 from Screens.SubtitleDisplay import SubtitleDisplay
34 from ServiceReference import ServiceReference
36 from Tools import Notifications
37 from Tools.Directories import *
39 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
46 from Components.config import config, currentConfigSelectionElement
49 from Menu import MainMenu, mdom
53 self.dishDialog = self.session.instantiateDialog(Dish)
54 self.onLayoutFinish.append(self.dishDialog.show)
56 class InfoBarShowHide:
57 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
65 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
67 "toggleShow": self.toggleShow,
71 self.__state = self.STATE_SHOWN
74 self.onExecBegin.append(self.show)
76 self.hideTimer = eTimer()
77 self.hideTimer.timeout.get().append(self.doTimerHide)
78 self.hideTimer.start(5000, True)
80 self.onShow.append(self.__onShow)
81 self.onHide.append(self.__onHide)
84 self.__state = self.STATE_SHOWN
87 def startHideTimer(self):
88 if self.__state == self.STATE_SHOWN and not self.__locked:
89 self.hideTimer.start(5000, True)
92 self.__state = self.STATE_HIDDEN
98 def doTimerHide(self):
100 if self.__state == self.STATE_SHOWN:
103 def toggleShow(self):
104 if self.__state == self.STATE_SHOWN:
106 self.hideTimer.stop()
107 elif self.__state == self.STATE_HIDDEN:
111 self.__locked = self.__locked + 1
114 self.hideTimer.stop()
116 def unlockShow(self):
117 self.__locked = self.__locked - 1
119 self.startHideTimer()
121 # def startShow(self):
122 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
123 # self.__state = self.STATE_SHOWN
125 # def startHide(self):
126 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
127 # self.__state = self.STATE_HIDDEN
129 class NumberZap(Screen):
136 self.close(int(self["number"].getText()))
138 def keyNumberGlobal(self, number):
139 self.Timer.start(3000, True) #reset timer
140 self.field = self.field + str(number)
141 self["number"].setText(self.field)
142 if len(self.field) >= 4:
145 def __init__(self, session, number):
146 Screen.__init__(self, session)
147 self.field = str(number)
149 self["channel"] = Label(_("Channel:"))
151 self["number"] = Label(self.field)
153 self["actions"] = NumberActionMap( [ "SetupActions" ],
157 "1": self.keyNumberGlobal,
158 "2": self.keyNumberGlobal,
159 "3": self.keyNumberGlobal,
160 "4": self.keyNumberGlobal,
161 "5": self.keyNumberGlobal,
162 "6": self.keyNumberGlobal,
163 "7": self.keyNumberGlobal,
164 "8": self.keyNumberGlobal,
165 "9": self.keyNumberGlobal,
166 "0": self.keyNumberGlobal
169 self.Timer = eTimer()
170 self.Timer.timeout.get().append(self.keyOK)
171 self.Timer.start(3000, True)
173 class InfoBarNumberZap:
174 """ Handles an initial number for NumberZapping """
176 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
178 "1": self.keyNumberGlobal,
179 "2": self.keyNumberGlobal,
180 "3": self.keyNumberGlobal,
181 "4": self.keyNumberGlobal,
182 "5": self.keyNumberGlobal,
183 "6": self.keyNumberGlobal,
184 "7": self.keyNumberGlobal,
185 "8": self.keyNumberGlobal,
186 "9": self.keyNumberGlobal,
187 "0": self.keyNumberGlobal,
190 def keyNumberGlobal(self, number):
191 # print "You pressed number " + str(number)
193 self.servicelist.recallPrevService()
196 self.session.openWithCallback(self.numberEntered, NumberZap, number)
198 def numberEntered(self, retval):
199 # print self.servicelist
201 self.zapToNumber(retval)
203 def searchNumberHelper(self, serviceHandler, num, bouquet):
204 servicelist = serviceHandler.list(bouquet)
205 if not servicelist is None:
207 serviceIterator = servicelist.getNext()
208 if not serviceIterator.valid(): #check end of list
210 if serviceIterator.flags: #assume normal dvb service have no flags set
213 if not num: #found service with searched number ?
214 return serviceIterator, 0
217 def zapToNumber(self, number):
218 bouquet = self.servicelist.bouquet_root
220 serviceHandler = eServiceCenter.getInstance()
221 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
222 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
224 bouquetlist = serviceHandler.list(bouquet)
225 if not bouquetlist is None:
227 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
228 if not bouquet.valid(): #check end of list
230 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
232 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233 if not service is None:
234 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
235 self.servicelist.clearPath()
236 if self.servicelist.bouquet_root != bouquet:
237 self.servicelist.enterPath(self.servicelist.bouquet_root)
238 self.servicelist.enterPath(bouquet)
239 self.servicelist.setCurrentSelection(service) #select the service in servicelist
240 self.servicelist.zap()
242 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
244 class InfoBarChannelSelection:
245 """ ChannelSelection - handles the channelSelection dialog and the initial
246 channelChange actions which open the channelSelection dialog """
249 self.servicelist = self.session.instantiateDialog(ChannelSelection)
251 if config.misc.initialchannelselection.value == 1:
252 self.onShown.append(self.firstRun)
254 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
256 "switchChannelUp": self.switchChannelUp,
257 "switchChannelDown": self.switchChannelDown,
258 "zapUp": (self.zapUp, _("previous channel")),
259 "zapDown": (self.zapDown, _("next channel")),
260 "historyBack": (self.historyBack, _("previous channel in history")),
261 "historyNext": (self.historyNext, _("next channel in history"))
265 self.onShown.remove(self.firstRun)
266 config.misc.initialchannelselection.value = 0
267 config.misc.initialchannelselection.save()
268 self.switchChannelDown()
270 def historyBack(self):
271 self.servicelist.historyBack()
273 def historyNext(self):
274 self.servicelist.historyNext()
276 def switchChannelUp(self):
277 self.servicelist.moveUp()
278 self.session.execDialog(self.servicelist)
280 def switchChannelDown(self):
281 self.servicelist.moveDown()
282 self.session.execDialog(self.servicelist)
285 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
286 if self.servicelist.inBouquet() and self.servicelist.atBegin():
287 self.servicelist.prevBouquet()
288 self.servicelist.moveUp()
289 self.servicelist.zap()
293 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
294 self.servicelist.nextBouquet()
296 self.servicelist.moveDown()
297 self.servicelist.zap()
301 """ Handles a menu action, to open the (main) menu """
303 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
305 "mainMenu": (self.mainMenu, "Enter main menu..."),
309 print "loading mainmenu XML..."
310 menu = mdom.childNodes[0]
311 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
312 self.session.open(MainMenu, menu, menu.childNodes)
314 class InfoBarSimpleEventView:
315 """ Opens the Eventview for now/next """
317 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
319 "showEventInfo": (self.openEventView, _("show event details")),
322 def openEventView(self):
324 service = self.session.nav.getCurrentService()
325 ref = self.session.nav.getCurrentlyPlayingServiceReference()
326 info = service.info()
329 self.epglist.append(ptr)
332 self.epglist.append(ptr)
333 if len(self.epglist) > 0:
334 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
336 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
337 if len(self.epglist) > 1:
338 tmp = self.epglist[0]
339 self.epglist[0]=self.epglist[1]
341 setEvent(self.epglist[0])
344 """ EPG - Opens an EPG list when the showEPGList action fires """
346 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
348 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
351 self.is_now_next = False
353 self.bouquetSel = None
354 self.eventView = None
355 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
357 "showEventInfo": (self.openEventView, _("show EPG...")),
360 def zapToService(self, service):
361 if not service is None:
362 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
363 self.servicelist.clearPath()
364 if self.servicelist.bouquet_root != self.epg_bouquet:
365 self.servicelist.enterPath(self.servicelist.bouquet_root)
366 self.servicelist.enterPath(self.epg_bouquet)
367 self.servicelist.setCurrentSelection(service) #select the service in servicelist
368 self.servicelist.zap()
370 def getBouquetServices(self, bouquet):
372 servicelist = eServiceCenter.getInstance().list(bouquet)
373 if not servicelist is None:
375 service = servicelist.getNext()
376 if not service.valid(): #check if end of list
378 if service.flags: #ignore non playable services
380 services.append(ServiceReference(service))
383 def openBouquetEPG(self, bouquet, withCallback=True):
384 services = self.getBouquetServices(bouquet)
386 self.epg_bouquet = bouquet
388 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
390 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
392 def changeBouquetCB(self, direction, epg):
395 self.bouquetSel.down()
398 bouquet = self.bouquetSel.getCurrent()
399 services = self.getBouquetServices(bouquet)
401 self.epg_bouquet = bouquet
402 epg.setServices(services)
404 def closed(self, ret=False):
405 closedScreen = self.dlg_stack.pop()
406 if self.bouquetSel and closedScreen == self.bouquetSel:
407 self.bouquetSel = None
408 elif self.eventView and closedScreen == self.eventView:
409 self.eventView = None
411 dlgs=len(self.dlg_stack)
413 self.dlg_stack[dlgs-1].close(dlgs > 1)
415 def openMultiServiceEPG(self, withCallback=True):
416 bouquets = self.servicelist.getBouquetList()
421 if cnt > 1: # show bouquet list
423 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
424 self.dlg_stack.append(self.bouquetSel)
426 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
428 self.openBouquetEPG(bouquets[0][1], withCallback)
430 def openSingleServiceEPG(self):
431 ref=self.session.nav.getCurrentlyPlayingServiceReference()
432 self.session.open(EPGSelection, ref)
434 def openSimilarList(self, eventid, refstr):
435 self.session.open(EPGSelection, refstr, None, eventid)
437 def getNowNext(self):
439 service = self.session.nav.getCurrentService()
440 info = service and service.info()
441 ptr = info and info.getEvent(0)
443 self.epglist.append(ptr)
444 ptr = info and info.getEvent(1)
446 self.epglist.append(ptr)
448 def __evEventInfoChanged(self):
449 if self.is_now_next and len(self.dlg_stack) == 1:
451 assert self.eventView
452 if len(self.epglist):
453 self.eventView.setEvent(self.epglist[0])
455 def openEventView(self):
456 ref = self.session.nav.getCurrentlyPlayingServiceReference()
458 if len(self.epglist) == 0:
459 self.is_now_next = False
460 epg = eEPGCache.getInstance()
461 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
463 self.epglist.append(ptr)
464 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
466 self.epglist.append(ptr)
468 self.is_now_next = True
469 if len(self.epglist) > 0:
470 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
471 self.dlg_stack.append(self.eventView)
473 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
474 self.openMultiServiceEPG(False)
476 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
477 if len(self.epglist) > 1:
478 tmp = self.epglist[0]
479 self.epglist[0]=self.epglist[1]
481 setEvent(self.epglist[0])
484 """provides a snr/agc/ber display"""
486 self["snr"] = Label()
487 self["agc"] = Label()
488 self["ber"] = Label()
489 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
490 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
491 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
492 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
493 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
494 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
495 self.timer = eTimer()
496 self.timer.timeout.get().append(self.updateTunerInfo)
497 self.timer.start(1000)
499 def updateTunerInfo(self):
500 if self.instance.isVisible():
501 self["snr_percent"].update()
502 self["agc_percent"].update()
503 self["ber_count"].update()
504 self["snr_progress"].update()
505 self["agc_progress"].update()
506 self["ber_progress"].update()
509 """provides a current/next event info display"""
511 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
512 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
514 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
515 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
517 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
518 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
520 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
522 class InfoBarServiceName:
524 self["ServiceName"] = ServiceName(self.session.nav)
527 """handles actions like seeking, pause"""
529 # ispause, isff, issm
530 SEEK_STATE_PLAY = (0, 0, 0, ">")
531 SEEK_STATE_PAUSE = (1, 0, 0, "||")
532 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
533 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
534 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
535 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
536 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
537 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
539 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
540 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
541 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
542 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
544 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
545 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
546 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
549 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
551 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
552 iPlayableService.evStart: self.__serviceStarted,
554 iPlayableService.evEOF: self.__evEOF,
555 iPlayableService.evSOF: self.__evSOF,
558 class InfoBarSeekActionMap(HelpableActionMap):
559 def __init__(self, screen, *args, **kwargs):
560 HelpableActionMap.__init__(self, screen, *args, **kwargs)
563 def action(self, contexts, action):
564 if action[:5] == "seek:":
565 time = int(action[5:])
566 self.screen.seekRelative(time * 90000)
569 return HelpableActionMap.action(self, contexts, action)
571 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
573 "pauseService": (self.pauseService, "pause"),
574 "unPauseService": (self.unPauseService, "continue"),
576 "seekFwd": (self.seekFwd, "skip forward"),
577 "seekFwdDown": self.seekFwdDown,
578 "seekFwdUp": self.seekFwdUp,
579 "seekBack": (self.seekBack, "skip backward"),
580 "seekBackDown": self.seekBackDown,
581 "seekBackUp": self.seekBackUp,
583 # give them a little more priority to win over color buttons
585 self.seekstate = self.SEEK_STATE_PLAY
586 self.onClose.append(self.delTimer)
588 self.fwdtimer = False
589 self.fwdKeyTimer = eTimer()
590 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
592 self.rwdtimer = False
593 self.rwdKeyTimer = eTimer()
594 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
596 self.onPlayStateChanged = [ ]
598 self.lockedBecauseOfSkipping = False
611 service = self.session.nav.getCurrentService()
615 seek = service.seek()
617 if seek is None or not seek.isCurrentlySeekable():
622 def isSeekable(self):
623 if self.getSeek() is None:
627 def __seekableStatusChanged(self):
628 print "seekable status changed!"
629 if not self.isSeekable():
630 self["SeekActions"].setEnabled(False)
631 print "not seekable, return to play"
632 self.setSeekState(self.SEEK_STATE_PLAY)
634 self["SeekActions"].setEnabled(True)
637 def __serviceStarted(self):
638 self.seekstate = self.SEEK_STATE_PLAY
640 def setSeekState(self, state):
641 service = self.session.nav.getCurrentService()
646 if not self.isSeekable():
647 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
648 state = self.SEEK_STATE_PLAY
650 pauseable = service.pause()
652 if pauseable is None:
653 print "not pauseable."
654 state = self.SEEK_STATE_PLAY
656 oldstate = self.seekstate
657 self.seekstate = state
660 if oldstate[i] != self.seekstate[i]:
661 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
663 for c in self.onPlayStateChanged:
666 self.checkSkipShowHideLock()
670 def pauseService(self):
671 if self.seekstate == self.SEEK_STATE_PAUSE:
672 print "pause, but in fact unpause"
673 self.unPauseService()
675 if self.seekstate == self.SEEK_STATE_PLAY:
676 print "yes, playing."
678 print "no", self.seekstate
680 self.setSeekState(self.SEEK_STATE_PAUSE);
682 def unPauseService(self):
684 self.setSeekState(self.SEEK_STATE_PLAY);
686 def doSeek(self, seektime):
687 print "doseek", seektime
688 service = self.session.nav.getCurrentService()
692 seekable = self.getSeek()
696 seekable.seekTo(90 * seektime)
698 def seekFwdDown(self):
699 print "start fwd timer"
701 self.fwdKeyTimer.start(1000)
703 def seekBackDown(self):
704 print "start rewind timer"
706 self.rwdKeyTimer.start(1000)
711 self.fwdKeyTimer.stop()
712 self.fwdtimer = False
717 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
718 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
719 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
720 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
721 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
722 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
723 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
724 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
725 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
726 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
727 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
728 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
729 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
730 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
731 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
733 self.setSeekState(lookup[self.seekstate])
735 def seekBackUp(self):
738 self.rwdKeyTimer.stop()
739 self.rwdtimer = False
744 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
745 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
746 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
747 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
748 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
749 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
750 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
751 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
752 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
753 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
754 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
755 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
756 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
757 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
758 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
760 self.setSeekState(lookup[self.seekstate])
762 if self.seekstate == self.SEEK_STATE_PAUSE:
763 seekable = self.getSeek()
764 if seekable is not None:
765 seekable.seekRelative(-1, 3)
767 def fwdTimerFire(self):
768 print "Display seek fwd"
769 self.fwdKeyTimer.stop()
770 self.fwdtimer = False
771 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
773 def fwdSeekTo(self, minutes):
774 print "Seek", minutes, "minutes forward"
776 seekable = self.getSeek()
777 if seekable is not None:
778 seekable.seekRelative(1, minutes * 60 * 90000)
780 def rwdTimerFire(self):
782 self.rwdKeyTimer.stop()
783 self.rwdtimer = False
784 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
786 def rwdSeekTo(self, minutes):
788 self.fwdSeekTo(0 - minutes)
790 def checkSkipShowHideLock(self):
791 wantlock = self.seekstate != self.SEEK_STATE_PLAY
793 if self.lockedBecauseOfSkipping and not wantlock:
795 self.lockedBecauseOfSkipping = False
797 if wantlock and not self.lockedBecauseOfSkipping:
799 self.lockedBecauseOfSkipping = True
802 if self.seekstate != self.SEEK_STATE_PLAY:
803 self.setSeekState(self.SEEK_STATE_PAUSE)
805 #self.getSeek().seekRelative(1, -90000)
806 self.setSeekState(self.SEEK_STATE_PLAY)
808 self.setSeekState(self.SEEK_STATE_PAUSE)
811 self.setSeekState(self.SEEK_STATE_PLAY)
814 def seekRelative(self, diff):
815 seekable = self.getSeek()
816 if seekable is not None:
817 seekable.seekRelative(1, diff)
819 from Screens.PVRState import PVRState, TimeshiftState
821 class InfoBarPVRState:
822 def __init__(self, screen=PVRState):
823 self.onPlayStateChanged.append(self.__playStateChanged)
824 self.pvrStateDialog = self.session.instantiateDialog(screen)
825 self.onShow.append(self.__mayShow)
826 self.onHide.append(self.pvrStateDialog.hide)
829 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
830 self.pvrStateDialog.show()
832 def __playStateChanged(self, state):
833 playstateString = state[3]
834 self.pvrStateDialog["state"].setText(playstateString)
837 class InfoBarTimeshiftState(InfoBarPVRState):
839 InfoBarPVRState.__init__(self, screen=TimeshiftState)
842 class InfoBarShowMovies:
844 # i don't really like this class.
845 # it calls a not further specified "movie list" on up/down/movieList,
846 # so this is not more than an action map
848 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
850 "movieList": (self.showMovies, "movie list"),
851 "up": (self.showMovies, "movie list"),
852 "down": (self.showMovies, "movie list")
855 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
859 # Timeshift works the following way:
860 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
861 # - normal playback TUNER unused PLAY enable disable disable
862 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
863 # - user presess pause again FILE record PLAY enable disable enable
864 # - user fast forwards FILE record FF enable disable enable
865 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
866 # - user backwards FILE record BACK # !! enable disable enable
870 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
871 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
872 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
873 # - the user can now PVR around
874 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
875 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
877 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
878 # - if the user rewinds, or press pause, timeshift will be activated again
880 # note that a timeshift can be enabled ("recording") and
881 # activated (currently time-shifting).
883 class InfoBarTimeshift:
885 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
887 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
888 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
890 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
892 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
893 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
894 }, prio=-1) # priority over record
896 self.timeshift_enabled = 0
897 self.timeshift_state = 0
898 self.ts_pause_timer = eTimer()
899 self.ts_pause_timer.timeout.get().append(self.pauseService)
901 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
903 iPlayableService.evStart: self.__serviceStarted,
904 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
907 def getTimeshift(self):
908 service = self.session.nav.getCurrentService()
909 return service and service.timeshift()
911 def startTimeshift(self):
912 print "enable timeshift"
913 ts = self.getTimeshift()
915 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
916 print "no ts interface"
919 if self.timeshift_enabled:
920 print "hu, timeshift already enabled?"
922 if not ts.startTimeshift():
924 self.timeshift_enabled = 1
925 self.pvrStateDialog["timeshift"].setRelative(time.time())
928 self.setSeekState(self.SEEK_STATE_PAUSE)
930 # enable the "TimeshiftEnableActions", which will override
931 # the startTimeshift actions
932 self.__seekableStatusChanged()
934 print "timeshift failed"
936 def stopTimeshift(self):
937 if not self.timeshift_enabled:
939 print "disable timeshift"
940 ts = self.getTimeshift()
943 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
945 def stopTimeshiftConfirmed(self, confirmed):
949 ts = self.getTimeshift()
954 self.timeshift_enabled = 0
957 self.__seekableStatusChanged()
959 # activates timeshift, and seeks to (almost) the end
960 def activateTimeshiftEnd(self):
961 ts = self.getTimeshift()
966 if ts.isTimeshiftActive():
967 print "!! activate timeshift called - but shouldn't this be a normal pause?"
970 self.setSeekState(self.SEEK_STATE_PLAY)
971 ts.activateTimeshift()
974 # same as activateTimeshiftEnd, but pauses afterwards.
975 def activateTimeshiftEndAndPause(self):
976 state = self.seekstate
977 self.activateTimeshiftEnd()
979 # well, this is "andPause", but it could be pressed from pause,
980 # when pausing on the (fake-)"live" picture, so an un-pause
983 print "now, pauseService"
984 if state == self.SEEK_STATE_PLAY:
985 print "is PLAYING, start pause timer"
986 self.ts_pause_timer.start(200, 1)
989 self.unPauseService()
991 def __seekableStatusChanged(self):
994 print "self.isSeekable", self.isSeekable()
995 print "self.timeshift_enabled", self.timeshift_enabled
997 # when this service is not seekable, but timeshift
998 # is enabled, this means we can activate
1000 if not self.isSeekable() and self.timeshift_enabled:
1003 print "timeshift activate:", enabled
1004 self["TimeshiftActivateActions"].setEnabled(enabled)
1006 def __serviceStarted(self):
1007 self.timeshift_enabled = False
1008 self.__seekableStatusChanged()
1010 from Screens.PiPSetup import PiPSetup
1012 class InfoBarExtensions:
1014 self.pipshown = False
1016 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1018 "extensions": (self.extensions, "Extensions..."),
1027 def extensions(self):
1029 if self.pipshown == False:
1030 list.append((_("Activate Picture in Picture"), self.PIPON))
1031 elif self.pipshown == True:
1032 list.append((_("Disable Picture in Picture"), self.PIPOFF))
1033 list.append((_("Move Picture in Picture"), self.MOVEPIP))
1034 list.append((_("Swap services"), self.PIPSWAP))
1036 s = self.getCurrentServiceSubtitle()
1037 l = s and s.getSubtitleList() or [ ]
1040 list.append(("DEBUG: Enable Subtitles: " + x[0], self.ENABLE_SUBTITLE, x))
1042 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
1044 def extensionCallback(self, answer):
1045 if answer is not None:
1046 if answer[1] == self.PIPON:
1047 self.pip = self.session.instantiateDialog(PictureInPicture)
1049 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1051 if self.pip.playService(newservice):
1052 self.pipshown = True
1054 self.pipshown = False
1056 self.session.nav.playService(newservice)
1057 elif answer[1] == self.PIPOFF:
1059 self.pipshown = False
1060 elif answer[1] == self.PIPSWAP:
1061 swapservice = self.pip.getCurrentService()
1062 self.pip.playService(self.session.nav.getCurrentlyPlayingServiceReference())
1063 self.session.nav.playService(swapservice)
1065 elif answer[1] == self.MOVEPIP:
1066 self.session.open(PiPSetup, pip = self.pip)
1067 elif answer[1] == self.ENABLE_SUBTITLE:
1068 self.selected_subtitle = answer[2]
1069 self.subtitles_enabled = True
1071 from RecordTimer import parseEvent
1073 class InfoBarInstantRecord:
1074 """Instant Record - handles the instantRecord action in order to
1075 start/stop instant records"""
1077 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1079 "instantRecord": (self.instantRecord, "Instant Record..."),
1082 self["BlinkingPoint"] = BlinkingPixmapConditional()
1083 self["BlinkingPoint"].hide()
1084 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1086 def stopCurrentRecording(self, entry = -1):
1087 if entry is not None and entry != -1:
1088 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1089 self.recording.remove(self.recording[entry])
1091 def startInstantRecording(self, limitEvent = False):
1092 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1094 # try to get event info
1097 service = self.session.nav.getCurrentService()
1098 epg = eEPGCache.getInstance()
1099 event = epg.lookupEventTime(serviceref, -1, 0)
1101 info = service.info()
1102 ev = info.getEvent(0)
1108 end = time.time() + 3600 * 10
1109 name = "instant record"
1113 if event is not None:
1114 curEvent = parseEvent(event)
1116 description = curEvent[3]
1117 eventid = curEvent[4]
1122 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1124 data = (begin, end, name, description, eventid)
1126 recording = self.session.nav.recordWithTimer(serviceref, *data)
1127 recording.dontSave = True
1128 self.recording.append(recording)
1130 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1132 def isInstantRecordRunning(self):
1133 print "self.recording:", self.recording
1134 if len(self.recording) > 0:
1135 for x in self.recording:
1140 def recordQuestionCallback(self, answer):
1141 print "pre:\n", self.recording
1143 if answer is None or answer[1] == "no":
1146 recording = self.recording[:]
1148 if not x in self.session.nav.RecordTimer.timer_list:
1149 self.recording.remove(x)
1150 elif x.dontSave and x.isRunning():
1151 list.append(TimerEntryComponent(x, False))
1153 if answer[1] == "changeduration":
1154 if len(self.recording) == 1:
1155 self.changeDuration(0)
1157 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1158 elif answer[1] == "stop":
1159 if len(self.recording) == 1:
1160 self.stopCurrentRecording(0)
1162 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1163 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1165 if answer[1] == "event":
1167 if answer[1] == "manualduration":
1168 self.selectedEntry = len(self.recording)
1169 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1170 self.startInstantRecording(limitEvent = limitEvent)
1172 print "after:\n", self.recording
1174 def changeDuration(self, entry):
1175 if entry is not None:
1176 self.selectedEntry = entry
1177 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1179 def inputCallback(self, value):
1180 if value is not None:
1181 print "stopping recording after", int(value), "minutes."
1182 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1183 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1185 def instantRecord(self):
1187 stat = os.stat(resolveFilename(SCOPE_HDD))
1189 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1192 if self.isInstantRecordRunning():
1193 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")])
1195 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")])
1197 from Tools.ISO639 import LanguageCodes
1199 class InfoBarAudioSelection:
1201 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1203 "audioSelection": (self.audioSelection, "Audio Options..."),
1206 def audioSelection(self):
1207 service = self.session.nav.getCurrentService()
1208 audio = service.audioTracks()
1209 self.audioTracks = audio
1210 n = audio.getNumberOfTracks()
1212 # self.audioChannel = service.audioChannel()
1213 # config.audio.audiochannel = configElement_nonSave("config.audio.audiochannel", configSelection, self.audioChannel.getCurrentChannel(), (("left", _("Left >")), ("stereo", _("< Stereo >")), ("right", _("< Right"))))
1216 i = audio.getTrackInfo(x)
1217 language = i.getLanguage()
1218 description = i.getDescription();
1220 if len(language) == 3:
1221 if language in LanguageCodes:
1222 language = LanguageCodes[language][0]
1224 if len(description):
1225 description += " (" + language + ")"
1227 description = language
1229 tlist.append((description, x))
1231 selectedAudio = tlist[0][1]
1232 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1234 # tlist.insert(0, getConfigListEntry(_("Audio Channel"), config.audio.audiochannel))
1238 if x[1] != selectedAudio:
1243 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection)
1245 del self.audioTracks
1247 def audioSelected(self, audio):
1248 if audio is not None:
1249 self.audioTracks.selectTrack(audio[1])
1250 del self.audioTracks
1251 # del self.audioChannel
1252 # del config.audio.audiochannel
1254 class InfoBarSubserviceSelection:
1256 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1258 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1261 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1263 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1264 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1266 self["SubserviceQuickzapAction"].setEnabled(False)
1268 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1270 def checkSubservicesAvail(self, ev):
1271 if ev == iPlayableService.evUpdatedEventInfo:
1272 service = self.session.nav.getCurrentService()
1273 subservices = service.subServices()
1274 if subservices.getNumberOfSubservices() == 0:
1275 self["SubserviceQuickzapAction"].setEnabled(False)
1277 def nextSubservice(self):
1278 self.changeSubservice(+1)
1280 def prevSubservice(self):
1281 self.changeSubservice(-1)
1283 def changeSubservice(self, direction):
1284 service = self.session.nav.getCurrentService()
1285 subservices = service.subServices()
1286 n = subservices.getNumberOfSubservices()
1289 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1291 if subservices.getSubservice(x).toString() == ref.toString():
1294 selection += direction
1299 newservice = subservices.getSubservice(selection)
1300 if newservice.valid():
1303 self.session.nav.playService(newservice)
1305 def subserviceSelection(self):
1306 service = self.session.nav.getCurrentService()
1307 subservices = service.subServices()
1309 n = subservices.getNumberOfSubservices()
1312 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1315 i = subservices.getSubservice(x)
1316 if i.toString() == ref.toString():
1318 tlist.append((i.getName(), i))
1320 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection)
1322 def subserviceSelected(self, service):
1323 if not service is None:
1324 self["SubserviceQuickzapAction"].setEnabled(True)
1325 self.session.nav.playService(service[1])
1327 class InfoBarAdditionalInfo:
1329 self["DolbyActive"] = Pixmap()
1330 self["CryptActive"] = Pixmap()
1331 self["FormatActive"] = Pixmap()
1333 self["ButtonRed"] = PixmapConditional(withTimer = False)
1334 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1335 self.onLayoutFinish.append(self["ButtonRed"].update)
1336 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1337 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1338 self.onLayoutFinish.append(self["ButtonRedText"].update)
1340 self["ButtonGreen"] = Pixmap()
1341 self["ButtonGreenText"] = Label(_("Subservices"))
1343 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1344 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1345 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1346 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1347 self.onLayoutFinish.append(self["ButtonYellow"].update)
1348 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1350 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1351 self["ButtonBlue"].setConnect(lambda: True)
1352 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1353 self["ButtonBlueText"].setConnect(lambda: True)
1354 self.onLayoutFinish.append(self["ButtonBlue"].update)
1355 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1357 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1359 def hideSubServiceIndication(self):
1360 self["ButtonGreen"].hide()
1361 self["ButtonGreenText"].hide()
1363 def showSubServiceIndication(self):
1364 self["ButtonGreen"].show()
1365 self["ButtonGreenText"].show()
1367 def checkFormat(self, service):
1368 info = service.info()
1369 if info is not None:
1370 aspect = info.getInfo(iServiceInformation.sAspect)
1371 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1372 self["FormatActive"].show()
1374 self["FormatActive"].hide()
1376 def checkSubservices(self, service):
1377 if service.subServices().getNumberOfSubservices() > 0:
1378 self.showSubServiceIndication()
1380 self.hideSubServiceIndication()
1382 def checkDolby(self, service):
1385 audio = service.audioTracks()
1386 if audio is not None:
1387 n = audio.getNumberOfTracks()
1389 i = audio.getTrackInfo(x)
1390 description = i.getDescription();
1391 if description.find("AC3") != -1 or description.find("DTS") != -1:
1395 self["DolbyActive"].show()
1397 self["DolbyActive"].hide()
1399 def checkCrypted(self, service):
1400 info = service.info()
1401 if info is not None:
1402 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1403 self["CryptActive"].show()
1405 self["CryptActive"].hide()
1407 def gotServiceEvent(self, ev):
1408 service = self.session.nav.getCurrentService()
1409 if ev == iPlayableService.evUpdatedEventInfo:
1410 self.checkSubservices(service)
1411 self.checkFormat(service)
1412 elif ev == iPlayableService.evUpdatedInfo:
1413 self.checkCrypted(service)
1414 self.checkDolby(service)
1415 elif ev == iPlayableService.evEnd:
1416 self.hideSubServiceIndication()
1417 self["CryptActive"].hide()
1418 self["DolbyActive"].hide()
1419 self["FormatActive"].hide()
1421 class InfoBarNotifications:
1423 self.onExecBegin.append(self.checkNotifications)
1424 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1425 self.onClose.append(self.__removeNotification)
1427 def __removeNotification(self):
1428 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1430 def checkNotificationsIfExecing(self):
1432 self.checkNotifications()
1434 def checkNotifications(self):
1435 if len(Notifications.notifications):
1436 n = Notifications.notifications[0]
1437 Notifications.notifications = Notifications.notifications[1:]
1440 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1442 self.session.open(n[1], *n[2], **n[3])
1444 class InfoBarServiceNotifications:
1446 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1448 iPlayableService.evEnd: self.serviceHasEnded
1451 def serviceHasEnded(self):
1452 print "service end!"
1455 self.setSeekState(self.SEEK_STATE_PLAY)
1459 class InfoBarCueSheetSupport:
1465 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1467 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1468 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1469 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1473 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1475 iPlayableService.evStart: self.__serviceStarted,
1478 def __serviceStarted(self):
1479 print "new service started! trying to download cuts!"
1480 self.downloadCuesheet()
1482 def __getSeekable(self):
1483 service = self.session.nav.getCurrentService()
1486 return service.seek()
1488 def cueGetCurrentPosition(self):
1489 seek = self.__getSeekable()
1492 r = seek.getPlayPosition()
1497 def jumpPreviousNextMark(self, cmp, alternative=None):
1498 current_pos = self.cueGetCurrentPosition()
1499 if current_pos is None:
1501 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1502 if mark is not None:
1504 elif alternative is not None:
1509 seekable = self.__getSeekable()
1510 if seekable is not None:
1511 seekable.seekTo(pts)
1513 def jumpPreviousMark(self):
1514 # we add 2 seconds, so if the play position is <2s after
1515 # the mark, the mark before will be used
1516 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1518 def jumpNextMark(self):
1519 self.jumpPreviousNextMark(lambda x: x)
1521 def getNearestCutPoint(self, pts, cmp=abs):
1524 for cp in self.cut_list:
1525 diff = cmp(cp[0] - pts)
1526 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1530 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1531 current_pos = self.cueGetCurrentPosition()
1532 if current_pos is None:
1533 print "not seekable"
1536 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1538 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1540 return nearest_cutpoint
1542 self.removeMark(nearest_cutpoint)
1543 elif not onlyremove and not onlyreturn:
1544 self.addMark((current_pos, self.CUT_TYPE_MARK))
1549 def addMark(self, point):
1550 bisect.insort(self.cut_list, point)
1551 self.uploadCuesheet()
1553 def removeMark(self, point):
1554 self.cut_list.remove(point)
1555 self.uploadCuesheet()
1557 def __getCuesheet(self):
1558 service = self.session.nav.getCurrentService()
1561 return service.cueSheet()
1563 def uploadCuesheet(self):
1564 cue = self.__getCuesheet()
1567 print "upload failed, no cuesheet interface"
1569 cue.setCutList(self.cut_list)
1571 def downloadCuesheet(self):
1572 cue = self.__getCuesheet()
1575 print "upload failed, no cuesheet interface"
1577 self.cut_list = cue.getCutList()
1579 class InfoBarSummary(Screen):
1581 <screen position="0,0" size="132,64">
1582 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1583 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1586 def __init__(self, session, parent):
1587 Screen.__init__(self, session)
1588 self["CurrentService"] = ServiceName(self.session.nav)
1589 self["Clock"] = Clock()
1591 class InfoBarSummarySupport:
1595 def createSummary(self):
1596 return InfoBarSummary
1598 class InfoBarTeletextPlugin:
1600 self.teletext_plugin = None
1602 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1603 self.teletext_plugin = p
1605 if self.teletext_plugin is not None:
1606 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1608 "startTeletext": (self.startTeletext, "View teletext...")
1611 print "no teletext plugin found!"
1613 def startTeletext(self):
1614 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1616 class InfoBarSubtitleSupport(object):
1618 object.__init__(self)
1619 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1620 self.__subtitles_enabled = False
1622 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1624 iPlayableService.evStart: self.__serviceStarted,
1627 def __serviceStarted(self):
1628 # reenable if it was enabled
1629 r = self.__subtitles_enabled
1630 self.__subtitles_enabled = False
1631 self.__selected_subtitle = None
1632 self.setSubtitlesEnable(r)
1634 def getCurrentServiceSubtitle(self):
1635 service = self.session.nav.getCurrentService()
1636 return service and service.subtitle()
1638 def setSubtitlesEnable(self, enable=True):
1639 subtitle = self.getCurrentServiceSubtitle()
1640 if enable and self.__selected_subtitle:
1641 if subtitle and not self.__subtitles_enabled:
1642 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle[1])
1643 self.subtitle_window.show()
1644 self.__subtitles_enabled = True
1647 subtitle.disableSubtitles(self.subtitle_window.instance)
1649 self.subtitle_window.hide()
1650 self.__subtitles_enabled = False
1652 def setSelectedSubtitle(self, subtitle):
1653 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1654 subtitle = self.getCurrentServiceSubtitle()
1657 self.__serviceStarted()
1658 self.__selected_subtitle = subtitle
1660 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1661 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)