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")),
262 "openServiceList": (self.openServiceList, _("open service list")),
266 self.onShown.remove(self.firstRun)
267 config.misc.initialchannelselection.value = 0
268 config.misc.initialchannelselection.save()
269 self.switchChannelDown()
271 def historyBack(self):
272 self.servicelist.historyBack()
274 def historyNext(self):
275 self.servicelist.historyNext()
277 def switchChannelUp(self):
278 self.servicelist.moveUp()
279 self.session.execDialog(self.servicelist)
281 def switchChannelDown(self):
282 self.servicelist.moveDown()
283 self.session.execDialog(self.servicelist)
285 def openServiceList(self):
286 self.session.execDialog(self.servicelist)
289 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
290 if self.servicelist.inBouquet() and self.servicelist.atBegin():
291 self.servicelist.prevBouquet()
292 self.servicelist.moveUp()
293 self.servicelist.zap()
297 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
298 self.servicelist.nextBouquet()
300 self.servicelist.moveDown()
301 self.servicelist.zap()
305 """ Handles a menu action, to open the (main) menu """
307 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
309 "mainMenu": (self.mainMenu, "Enter main menu..."),
313 print "loading mainmenu XML..."
314 menu = mdom.childNodes[0]
315 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
316 self.session.open(MainMenu, menu, menu.childNodes)
318 class InfoBarSimpleEventView:
319 """ Opens the Eventview for now/next """
321 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
323 "showEventInfo": (self.openEventView, _("show event details")),
326 def openEventView(self):
328 service = self.session.nav.getCurrentService()
329 ref = self.session.nav.getCurrentlyPlayingServiceReference()
330 info = service.info()
333 self.epglist.append(ptr)
336 self.epglist.append(ptr)
337 if len(self.epglist) > 0:
338 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
340 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
341 if len(self.epglist) > 1:
342 tmp = self.epglist[0]
343 self.epglist[0]=self.epglist[1]
345 setEvent(self.epglist[0])
348 """ EPG - Opens an EPG list when the showEPGList action fires """
350 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
352 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
355 self.is_now_next = False
357 self.bouquetSel = None
358 self.eventView = None
359 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
361 "showEventInfo": (self.openEventView, _("show EPG...")),
364 def zapToService(self, service):
365 if not service is None:
366 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
367 self.servicelist.clearPath()
368 if self.servicelist.bouquet_root != self.epg_bouquet:
369 self.servicelist.enterPath(self.servicelist.bouquet_root)
370 self.servicelist.enterPath(self.epg_bouquet)
371 self.servicelist.setCurrentSelection(service) #select the service in servicelist
372 self.servicelist.zap()
374 def getBouquetServices(self, bouquet):
376 servicelist = eServiceCenter.getInstance().list(bouquet)
377 if not servicelist is None:
379 service = servicelist.getNext()
380 if not service.valid(): #check if end of list
382 if service.flags: #ignore non playable services
384 services.append(ServiceReference(service))
387 def openBouquetEPG(self, bouquet, withCallback=True):
388 services = self.getBouquetServices(bouquet)
390 self.epg_bouquet = bouquet
392 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
394 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
396 def changeBouquetCB(self, direction, epg):
399 self.bouquetSel.down()
402 bouquet = self.bouquetSel.getCurrent()
403 services = self.getBouquetServices(bouquet)
405 self.epg_bouquet = bouquet
406 epg.setServices(services)
408 def closed(self, ret=False):
409 closedScreen = self.dlg_stack.pop()
410 if self.bouquetSel and closedScreen == self.bouquetSel:
411 self.bouquetSel = None
412 elif self.eventView and closedScreen == self.eventView:
413 self.eventView = None
415 dlgs=len(self.dlg_stack)
417 self.dlg_stack[dlgs-1].close(dlgs > 1)
419 def openMultiServiceEPG(self, withCallback=True):
420 bouquets = self.servicelist.getBouquetList()
425 if cnt > 1: # show bouquet list
427 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
428 self.dlg_stack.append(self.bouquetSel)
430 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
432 self.openBouquetEPG(bouquets[0][1], withCallback)
434 def openSingleServiceEPG(self):
435 ref=self.session.nav.getCurrentlyPlayingServiceReference()
436 self.session.open(EPGSelection, ref)
438 def openSimilarList(self, eventid, refstr):
439 self.session.open(EPGSelection, refstr, None, eventid)
441 def getNowNext(self):
443 service = self.session.nav.getCurrentService()
444 info = service and service.info()
445 ptr = info and info.getEvent(0)
447 self.epglist.append(ptr)
448 ptr = info and info.getEvent(1)
450 self.epglist.append(ptr)
452 def __evEventInfoChanged(self):
453 if self.is_now_next and len(self.dlg_stack) == 1:
455 assert self.eventView
456 if len(self.epglist):
457 self.eventView.setEvent(self.epglist[0])
459 def openEventView(self):
460 ref = self.session.nav.getCurrentlyPlayingServiceReference()
462 if len(self.epglist) == 0:
463 self.is_now_next = False
464 epg = eEPGCache.getInstance()
465 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
467 self.epglist.append(ptr)
468 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
470 self.epglist.append(ptr)
472 self.is_now_next = True
473 if len(self.epglist) > 0:
474 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
475 self.dlg_stack.append(self.eventView)
477 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
478 self.openMultiServiceEPG(False)
480 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
481 if len(self.epglist) > 1:
482 tmp = self.epglist[0]
483 self.epglist[0]=self.epglist[1]
485 setEvent(self.epglist[0])
488 """provides a snr/agc/ber display"""
490 self["snr"] = Label()
491 self["agc"] = Label()
492 self["ber"] = Label()
493 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
494 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
495 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
496 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
497 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
498 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
499 self.timer = eTimer()
500 self.timer.timeout.get().append(self.updateTunerInfo)
501 self.timer.start(1000)
503 def updateTunerInfo(self):
504 if self.instance.isVisible():
505 self["snr_percent"].update()
506 self["agc_percent"].update()
507 self["ber_count"].update()
508 self["snr_progress"].update()
509 self["agc_progress"].update()
510 self["ber_progress"].update()
513 """provides a current/next event info display"""
515 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
516 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
518 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
519 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
521 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
522 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
524 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
526 class InfoBarServiceName:
528 self["ServiceName"] = ServiceName(self.session.nav)
531 """handles actions like seeking, pause"""
533 # ispause, isff, issm
534 SEEK_STATE_PLAY = (0, 0, 0, ">")
535 SEEK_STATE_PAUSE = (1, 0, 0, "||")
536 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
537 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
538 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
539 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
540 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
541 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
543 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
544 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
545 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
546 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
548 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
549 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
550 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
553 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
555 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
556 iPlayableService.evStart: self.__serviceStarted,
558 iPlayableService.evEOF: self.__evEOF,
559 iPlayableService.evSOF: self.__evSOF,
562 class InfoBarSeekActionMap(HelpableActionMap):
563 def __init__(self, screen, *args, **kwargs):
564 HelpableActionMap.__init__(self, screen, *args, **kwargs)
567 def action(self, contexts, action):
568 if action[:5] == "seek:":
569 time = int(action[5:])
570 self.screen.seekRelative(time * 90000)
573 return HelpableActionMap.action(self, contexts, action)
575 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
577 "pauseService": (self.pauseService, "pause"),
578 "unPauseService": (self.unPauseService, "continue"),
580 "seekFwd": (self.seekFwd, "skip forward"),
581 "seekFwdDown": self.seekFwdDown,
582 "seekFwdUp": self.seekFwdUp,
583 "seekBack": (self.seekBack, "skip backward"),
584 "seekBackDown": self.seekBackDown,
585 "seekBackUp": self.seekBackUp,
587 # give them a little more priority to win over color buttons
589 self.seekstate = self.SEEK_STATE_PLAY
590 self.onClose.append(self.delTimer)
592 self.fwdtimer = False
593 self.fwdKeyTimer = eTimer()
594 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
596 self.rwdtimer = False
597 self.rwdKeyTimer = eTimer()
598 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
600 self.onPlayStateChanged = [ ]
602 self.lockedBecauseOfSkipping = False
615 service = self.session.nav.getCurrentService()
619 seek = service.seek()
621 if seek is None or not seek.isCurrentlySeekable():
626 def isSeekable(self):
627 if self.getSeek() is None:
631 def __seekableStatusChanged(self):
632 print "seekable status changed!"
633 if not self.isSeekable():
634 self["SeekActions"].setEnabled(False)
635 print "not seekable, return to play"
636 self.setSeekState(self.SEEK_STATE_PLAY)
638 self["SeekActions"].setEnabled(True)
641 def __serviceStarted(self):
642 self.seekstate = self.SEEK_STATE_PLAY
644 def setSeekState(self, state):
645 service = self.session.nav.getCurrentService()
650 if not self.isSeekable():
651 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
652 state = self.SEEK_STATE_PLAY
654 pauseable = service.pause()
656 if pauseable is None:
657 print "not pauseable."
658 state = self.SEEK_STATE_PLAY
660 oldstate = self.seekstate
661 self.seekstate = state
664 if oldstate[i] != self.seekstate[i]:
665 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
667 for c in self.onPlayStateChanged:
670 self.checkSkipShowHideLock()
674 def pauseService(self):
675 if self.seekstate == self.SEEK_STATE_PAUSE:
676 print "pause, but in fact unpause"
677 self.unPauseService()
679 if self.seekstate == self.SEEK_STATE_PLAY:
680 print "yes, playing."
682 print "no", self.seekstate
684 self.setSeekState(self.SEEK_STATE_PAUSE);
686 def unPauseService(self):
688 if self.seekstate == self.SEEK_STATE_PLAY:
690 self.setSeekState(self.SEEK_STATE_PLAY);
692 def doSeek(self, seektime):
693 print "doseek", seektime
694 service = self.session.nav.getCurrentService()
698 seekable = self.getSeek()
702 seekable.seekTo(90 * seektime)
704 def seekFwdDown(self):
705 print "start fwd timer"
707 self.fwdKeyTimer.start(1000)
709 def seekBackDown(self):
710 print "start rewind timer"
712 self.rwdKeyTimer.start(1000)
717 self.fwdKeyTimer.stop()
718 self.fwdtimer = False
723 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
724 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
725 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
726 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
727 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
728 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
729 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
730 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
731 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
732 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
733 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
734 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
735 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
736 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
737 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
739 self.setSeekState(lookup[self.seekstate])
741 def seekBackUp(self):
744 self.rwdKeyTimer.stop()
745 self.rwdtimer = False
750 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
751 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
752 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
753 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
754 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
755 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
756 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
757 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
758 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
759 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
760 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
761 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
762 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
763 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
764 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
766 self.setSeekState(lookup[self.seekstate])
768 if self.seekstate == self.SEEK_STATE_PAUSE:
769 seekable = self.getSeek()
770 if seekable is not None:
771 seekable.seekRelative(-1, 3)
773 def fwdTimerFire(self):
774 print "Display seek fwd"
775 self.fwdKeyTimer.stop()
776 self.fwdtimer = False
777 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
779 def fwdSeekTo(self, minutes):
780 print "Seek", minutes, "minutes forward"
782 seekable = self.getSeek()
783 if seekable is not None:
784 seekable.seekRelative(1, minutes * 60 * 90000)
786 def rwdTimerFire(self):
788 self.rwdKeyTimer.stop()
789 self.rwdtimer = False
790 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
792 def rwdSeekTo(self, minutes):
794 self.fwdSeekTo(0 - minutes)
796 def checkSkipShowHideLock(self):
797 wantlock = self.seekstate != self.SEEK_STATE_PLAY
799 if self.lockedBecauseOfSkipping and not wantlock:
801 self.lockedBecauseOfSkipping = False
803 if wantlock and not self.lockedBecauseOfSkipping:
805 self.lockedBecauseOfSkipping = True
808 if self.seekstate != self.SEEK_STATE_PLAY:
809 self.setSeekState(self.SEEK_STATE_PAUSE)
811 #self.getSeek().seekRelative(1, -90000)
812 self.setSeekState(self.SEEK_STATE_PLAY)
814 self.setSeekState(self.SEEK_STATE_PAUSE)
817 self.setSeekState(self.SEEK_STATE_PLAY)
820 def seekRelative(self, diff):
821 seekable = self.getSeek()
822 if seekable is not None:
823 seekable.seekRelative(1, diff)
825 from Screens.PVRState import PVRState, TimeshiftState
827 class InfoBarPVRState:
828 def __init__(self, screen=PVRState):
829 self.onPlayStateChanged.append(self.__playStateChanged)
830 self.pvrStateDialog = self.session.instantiateDialog(screen)
831 self.onShow.append(self.__mayShow)
832 self.onHide.append(self.pvrStateDialog.hide)
835 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
836 self.pvrStateDialog.show()
838 def __playStateChanged(self, state):
839 playstateString = state[3]
840 self.pvrStateDialog["state"].setText(playstateString)
843 class InfoBarTimeshiftState(InfoBarPVRState):
845 InfoBarPVRState.__init__(self, screen=TimeshiftState)
848 class InfoBarShowMovies:
850 # i don't really like this class.
851 # it calls a not further specified "movie list" on up/down/movieList,
852 # so this is not more than an action map
854 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
856 "movieList": (self.showMovies, "movie list"),
857 "up": (self.showMovies, "movie list"),
858 "down": (self.showMovies, "movie list")
861 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
865 # Timeshift works the following way:
866 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
867 # - normal playback TUNER unused PLAY enable disable disable
868 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
869 # - user presess pause again FILE record PLAY enable disable enable
870 # - user fast forwards FILE record FF enable disable enable
871 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
872 # - user backwards FILE record BACK # !! enable disable enable
876 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
877 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
878 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
879 # - the user can now PVR around
880 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
881 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
883 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
884 # - if the user rewinds, or press pause, timeshift will be activated again
886 # note that a timeshift can be enabled ("recording") and
887 # activated (currently time-shifting).
889 class InfoBarTimeshift:
891 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
893 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
894 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
896 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
898 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
899 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
900 }, prio=-1) # priority over record
902 self.timeshift_enabled = 0
903 self.timeshift_state = 0
904 self.ts_pause_timer = eTimer()
905 self.ts_pause_timer.timeout.get().append(self.pauseService)
907 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
909 iPlayableService.evStart: self.__serviceStarted,
910 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
913 def getTimeshift(self):
914 service = self.session.nav.getCurrentService()
915 return service and service.timeshift()
917 def startTimeshift(self):
918 print "enable timeshift"
919 ts = self.getTimeshift()
921 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
922 print "no ts interface"
925 if self.timeshift_enabled:
926 print "hu, timeshift already enabled?"
928 if not ts.startTimeshift():
930 self.timeshift_enabled = 1
931 self.pvrStateDialog["timeshift"].setRelative(time.time())
934 self.setSeekState(self.SEEK_STATE_PAUSE)
936 # enable the "TimeshiftEnableActions", which will override
937 # the startTimeshift actions
938 self.__seekableStatusChanged()
940 print "timeshift failed"
942 def stopTimeshift(self):
943 if not self.timeshift_enabled:
945 print "disable timeshift"
946 ts = self.getTimeshift()
949 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
951 def stopTimeshiftConfirmed(self, confirmed):
955 ts = self.getTimeshift()
960 self.timeshift_enabled = 0
963 self.__seekableStatusChanged()
965 # activates timeshift, and seeks to (almost) the end
966 def activateTimeshiftEnd(self):
967 ts = self.getTimeshift()
972 if ts.isTimeshiftActive():
973 print "!! activate timeshift called - but shouldn't this be a normal pause?"
976 self.setSeekState(self.SEEK_STATE_PLAY)
977 ts.activateTimeshift()
980 # same as activateTimeshiftEnd, but pauses afterwards.
981 def activateTimeshiftEndAndPause(self):
982 state = self.seekstate
983 self.activateTimeshiftEnd()
985 # well, this is "andPause", but it could be pressed from pause,
986 # when pausing on the (fake-)"live" picture, so an un-pause
989 print "now, pauseService"
990 if state == self.SEEK_STATE_PLAY:
991 print "is PLAYING, start pause timer"
992 self.ts_pause_timer.start(200, 1)
995 self.unPauseService()
997 def __seekableStatusChanged(self):
1000 print "self.isSeekable", self.isSeekable()
1001 print "self.timeshift_enabled", self.timeshift_enabled
1003 # when this service is not seekable, but timeshift
1004 # is enabled, this means we can activate
1006 if not self.isSeekable() and self.timeshift_enabled:
1009 print "timeshift activate:", enabled
1010 self["TimeshiftActivateActions"].setEnabled(enabled)
1012 def __serviceStarted(self):
1013 self.timeshift_enabled = False
1014 self.__seekableStatusChanged()
1016 from Screens.PiPSetup import PiPSetup
1018 class InfoBarExtensions:
1020 self.pipshown = False
1022 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1024 "extensions": (self.extensions, "Extensions..."),
1033 def extensions(self):
1035 if self.pipshown == False:
1036 list.append((_("Activate Picture in Picture"), self.PIPON))
1037 elif self.pipshown == True:
1038 list.append((_("Disable Picture in Picture"), self.PIPOFF))
1039 list.append((_("Move Picture in Picture"), self.MOVEPIP))
1040 list.append((_("Swap services"), self.PIPSWAP))
1042 s = self.getCurrentServiceSubtitle()
1043 l = s and s.getSubtitleList() or [ ]
1046 list.append(("DEBUG: Enable Subtitles: " + x[0], self.ENABLE_SUBTITLE, x[1]))
1048 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
1050 def extensionCallback(self, answer):
1051 if answer is not None:
1052 if answer[1] == self.PIPON:
1053 self.pip = self.session.instantiateDialog(PictureInPicture)
1055 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1057 if self.pip.playService(newservice):
1058 self.pipshown = True
1060 self.pipshown = False
1062 self.session.nav.playService(newservice)
1063 elif answer[1] == self.PIPOFF:
1065 self.pipshown = False
1066 elif answer[1] == self.PIPSWAP:
1067 swapservice = self.pip.getCurrentService()
1068 self.pip.playService(self.session.nav.getCurrentlyPlayingServiceReference())
1069 self.session.nav.playService(swapservice)
1071 elif answer[1] == self.MOVEPIP:
1072 self.session.open(PiPSetup, pip = self.pip)
1073 elif answer[1] == self.ENABLE_SUBTITLE:
1074 self.selected_subtitle = answer[2]
1075 self.subtitles_enabled = True
1077 from RecordTimer import parseEvent
1079 class InfoBarInstantRecord:
1080 """Instant Record - handles the instantRecord action in order to
1081 start/stop instant records"""
1083 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1085 "instantRecord": (self.instantRecord, "Instant Record..."),
1088 self["BlinkingPoint"] = BlinkingPixmapConditional()
1089 self["BlinkingPoint"].hide()
1090 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1092 def stopCurrentRecording(self, entry = -1):
1093 if entry is not None and entry != -1:
1094 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1095 self.recording.remove(self.recording[entry])
1097 def startInstantRecording(self, limitEvent = False):
1098 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1100 # try to get event info
1103 service = self.session.nav.getCurrentService()
1104 epg = eEPGCache.getInstance()
1105 event = epg.lookupEventTime(serviceref, -1, 0)
1107 info = service.info()
1108 ev = info.getEvent(0)
1114 end = time.time() + 3600 * 10
1115 name = "instant record"
1119 if event is not None:
1120 curEvent = parseEvent(event)
1122 description = curEvent[3]
1123 eventid = curEvent[4]
1128 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1130 data = (begin, end, name, description, eventid)
1132 recording = self.session.nav.recordWithTimer(serviceref, *data)
1133 recording.dontSave = True
1134 self.recording.append(recording)
1136 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1138 def isInstantRecordRunning(self):
1139 print "self.recording:", self.recording
1140 if len(self.recording) > 0:
1141 for x in self.recording:
1146 def recordQuestionCallback(self, answer):
1147 print "pre:\n", self.recording
1149 if answer is None or answer[1] == "no":
1152 recording = self.recording[:]
1154 if not x in self.session.nav.RecordTimer.timer_list:
1155 self.recording.remove(x)
1156 elif x.dontSave and x.isRunning():
1157 list.append(TimerEntryComponent(x, False))
1159 if answer[1] == "changeduration":
1160 if len(self.recording) == 1:
1161 self.changeDuration(0)
1163 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1164 elif answer[1] == "stop":
1165 if len(self.recording) == 1:
1166 self.stopCurrentRecording(0)
1168 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1169 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1171 if answer[1] == "event":
1173 if answer[1] == "manualduration":
1174 self.selectedEntry = len(self.recording)
1175 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1176 self.startInstantRecording(limitEvent = limitEvent)
1178 print "after:\n", self.recording
1180 def changeDuration(self, entry):
1181 if entry is not None:
1182 self.selectedEntry = entry
1183 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1185 def inputCallback(self, value):
1186 if value is not None:
1187 print "stopping recording after", int(value), "minutes."
1188 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1189 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1191 def instantRecord(self):
1193 stat = os.stat(resolveFilename(SCOPE_HDD))
1195 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1198 if self.isInstantRecordRunning():
1199 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")])
1201 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")])
1203 from Tools.ISO639 import LanguageCodes
1205 class InfoBarAudioSelection:
1207 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1209 "audioSelection": (self.audioSelection, "Audio Options..."),
1212 def audioSelection(self):
1213 service = self.session.nav.getCurrentService()
1214 audio = service.audioTracks()
1215 self.audioTracks = audio
1216 n = audio.getNumberOfTracks()
1218 # self.audioChannel = service.audioChannel()
1219 # config.audio.audiochannel = configElement_nonSave("config.audio.audiochannel", configSelection, self.audioChannel.getCurrentChannel(), (("left", _("Left >")), ("stereo", _("< Stereo >")), ("right", _("< Right"))))
1222 i = audio.getTrackInfo(x)
1223 language = i.getLanguage()
1224 description = i.getDescription();
1226 if len(language) == 3:
1227 if language in LanguageCodes:
1228 language = LanguageCodes[language][0]
1230 if len(description):
1231 description += " (" + language + ")"
1233 description = language
1235 tlist.append((description, x))
1237 selectedAudio = tlist[0][1]
1238 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1240 # tlist.insert(0, getConfigListEntry(_("Audio Channel"), config.audio.audiochannel))
1244 if x[1] != selectedAudio:
1249 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection)
1251 del self.audioTracks
1253 def audioSelected(self, audio):
1254 if audio is not None:
1255 self.audioTracks.selectTrack(audio[1])
1256 del self.audioTracks
1257 # del self.audioChannel
1258 # del config.audio.audiochannel
1260 class InfoBarSubserviceSelection:
1262 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1264 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1267 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1269 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1270 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1272 self["SubserviceQuickzapAction"].setEnabled(False)
1274 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1276 def checkSubservicesAvail(self, ev):
1277 if ev == iPlayableService.evUpdatedEventInfo:
1278 service = self.session.nav.getCurrentService()
1279 subservices = service.subServices()
1280 if subservices.getNumberOfSubservices() == 0:
1281 self["SubserviceQuickzapAction"].setEnabled(False)
1283 def nextSubservice(self):
1284 self.changeSubservice(+1)
1286 def prevSubservice(self):
1287 self.changeSubservice(-1)
1289 def changeSubservice(self, direction):
1290 service = self.session.nav.getCurrentService()
1291 subservices = service.subServices()
1292 n = subservices.getNumberOfSubservices()
1295 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1297 if subservices.getSubservice(x).toString() == ref.toString():
1300 selection += direction
1305 newservice = subservices.getSubservice(selection)
1306 if newservice.valid():
1309 self.session.nav.playService(newservice)
1311 def subserviceSelection(self):
1312 service = self.session.nav.getCurrentService()
1313 subservices = service.subServices()
1315 n = subservices.getNumberOfSubservices()
1318 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1321 i = subservices.getSubservice(x)
1322 if i.toString() == ref.toString():
1324 tlist.append((i.getName(), i))
1326 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection)
1328 def subserviceSelected(self, service):
1329 if not service is None:
1330 self["SubserviceQuickzapAction"].setEnabled(True)
1331 self.session.nav.playService(service[1])
1333 class InfoBarAdditionalInfo:
1335 self["DolbyActive"] = Pixmap()
1336 self["CryptActive"] = Pixmap()
1337 self["FormatActive"] = Pixmap()
1339 self["ButtonRed"] = PixmapConditional(withTimer = False)
1340 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1341 self.onLayoutFinish.append(self["ButtonRed"].update)
1342 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1343 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1344 self.onLayoutFinish.append(self["ButtonRedText"].update)
1346 self["ButtonGreen"] = Pixmap()
1347 self["ButtonGreenText"] = Label(_("Subservices"))
1349 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1350 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1351 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1352 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1353 self.onLayoutFinish.append(self["ButtonYellow"].update)
1354 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1356 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1357 self["ButtonBlue"].setConnect(lambda: True)
1358 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1359 self["ButtonBlueText"].setConnect(lambda: True)
1360 self.onLayoutFinish.append(self["ButtonBlue"].update)
1361 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1363 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1365 def hideSubServiceIndication(self):
1366 self["ButtonGreen"].hide()
1367 self["ButtonGreenText"].hide()
1369 def showSubServiceIndication(self):
1370 self["ButtonGreen"].show()
1371 self["ButtonGreenText"].show()
1373 def checkFormat(self, service):
1374 info = service.info()
1375 if info is not None:
1376 aspect = info.getInfo(iServiceInformation.sAspect)
1377 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1378 self["FormatActive"].show()
1380 self["FormatActive"].hide()
1382 def checkSubservices(self, service):
1383 if service.subServices().getNumberOfSubservices() > 0:
1384 self.showSubServiceIndication()
1386 self.hideSubServiceIndication()
1388 def checkDolby(self, service):
1391 audio = service.audioTracks()
1392 if audio is not None:
1393 n = audio.getNumberOfTracks()
1395 i = audio.getTrackInfo(x)
1396 description = i.getDescription();
1397 if description.find("AC3") != -1 or description.find("DTS") != -1:
1401 self["DolbyActive"].show()
1403 self["DolbyActive"].hide()
1405 def checkCrypted(self, service):
1406 info = service.info()
1407 if info is not None:
1408 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1409 self["CryptActive"].show()
1411 self["CryptActive"].hide()
1413 def gotServiceEvent(self, ev):
1414 service = self.session.nav.getCurrentService()
1415 if ev == iPlayableService.evUpdatedEventInfo:
1416 self.checkSubservices(service)
1417 self.checkFormat(service)
1418 elif ev == iPlayableService.evUpdatedInfo:
1419 self.checkCrypted(service)
1420 self.checkDolby(service)
1421 elif ev == iPlayableService.evEnd:
1422 self.hideSubServiceIndication()
1423 self["CryptActive"].hide()
1424 self["DolbyActive"].hide()
1425 self["FormatActive"].hide()
1427 class InfoBarNotifications:
1429 self.onExecBegin.append(self.checkNotifications)
1430 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1431 self.onClose.append(self.__removeNotification)
1433 def __removeNotification(self):
1434 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1436 def checkNotificationsIfExecing(self):
1438 self.checkNotifications()
1440 def checkNotifications(self):
1441 if len(Notifications.notifications):
1442 n = Notifications.notifications[0]
1443 Notifications.notifications = Notifications.notifications[1:]
1446 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1448 self.session.open(n[1], *n[2], **n[3])
1450 class InfoBarServiceNotifications:
1452 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1454 iPlayableService.evEnd: self.serviceHasEnded
1457 def serviceHasEnded(self):
1458 print "service end!"
1461 self.setSeekState(self.SEEK_STATE_PLAY)
1465 class InfoBarCueSheetSupport:
1471 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1473 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1474 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1475 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1479 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1481 iPlayableService.evStart: self.__serviceStarted,
1484 def __serviceStarted(self):
1485 print "new service started! trying to download cuts!"
1486 self.downloadCuesheet()
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 name="Clock" position="50,46" size="82,18" font="Regular;16" />
1589 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1592 def __init__(self, session, parent):
1593 Screen.__init__(self, session)
1594 self["CurrentService"] = ServiceName(self.session.nav)
1595 self["Clock"] = Clock()
1597 class InfoBarSummarySupport:
1601 def createSummary(self):
1602 return InfoBarSummary
1604 class InfoBarTeletextPlugin:
1606 self.teletext_plugin = None
1608 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1609 self.teletext_plugin = p
1611 if self.teletext_plugin is not None:
1612 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1614 "startTeletext": (self.startTeletext, "View teletext...")
1617 print "no teletext plugin found!"
1619 def startTeletext(self):
1620 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1622 class InfoBarSubtitleSupport(object):
1624 object.__init__(self)
1625 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1626 self.__subtitles_enabled = False
1628 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1630 iPlayableService.evStart: self.__serviceStarted,
1633 def __serviceStarted(self):
1634 # reenable if it was enabled
1635 r = self.__subtitles_enabled
1636 self.__subtitles_enabled = False
1637 self.__selected_subtitle = None
1638 self.setSubtitlesEnable(r)
1640 def getCurrentServiceSubtitle(self):
1641 service = self.session.nav.getCurrentService()
1642 return service and service.subtitle()
1644 def setSubtitlesEnable(self, enable=True):
1645 subtitle = self.getCurrentServiceSubtitle()
1646 if enable and self.__selected_subtitle:
1647 if subtitle and not self.__subtitles_enabled:
1648 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1649 self.subtitle_window.show()
1650 self.__subtitles_enabled = True
1653 subtitle.disableSubtitles(self.subtitle_window.instance)
1655 self.subtitle_window.hide()
1656 self.__subtitles_enabled = False
1658 def setSelectedSubtitle(self, subtitle):
1659 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1661 self.__selected_subtitle = subtitle
1662 self.__serviceStarted()
1664 self.__selected_subtitle = subtitle
1666 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1667 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)