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 ServiceReference import ServiceReference
35 from Tools import Notifications
36 from Tools.Directories import *
38 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
45 from Components.config import config, currentConfigSelectionElement
48 from Menu import MainMenu, mdom
52 self.dishDialog = self.session.instantiateDialog(Dish)
53 self.onLayoutFinish.append(self.dishDialog.show)
55 class InfoBarShowHide:
56 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
64 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66 "toggleShow": self.toggleShow,
70 self.__state = self.STATE_SHOWN
73 self.onExecBegin.append(self.show)
75 self.hideTimer = eTimer()
76 self.hideTimer.timeout.get().append(self.doTimerHide)
77 self.hideTimer.start(5000, True)
79 self.onShow.append(self.__onShow)
80 self.onHide.append(self.__onHide)
83 self.__state = self.STATE_SHOWN
86 def startHideTimer(self):
87 if self.__state == self.STATE_SHOWN and not self.__locked:
88 self.hideTimer.start(5000, True)
91 self.__state = self.STATE_HIDDEN
97 def doTimerHide(self):
99 if self.__state == self.STATE_SHOWN:
102 def toggleShow(self):
103 if self.__state == self.STATE_SHOWN:
105 self.hideTimer.stop()
106 elif self.__state == self.STATE_HIDDEN:
110 self.__locked = self.__locked + 1
113 self.hideTimer.stop()
115 def unlockShow(self):
116 self.__locked = self.__locked - 1
118 self.startHideTimer()
120 # def startShow(self):
121 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
122 # self.__state = self.STATE_SHOWN
124 # def startHide(self):
125 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
126 # self.__state = self.STATE_HIDDEN
128 class NumberZap(Screen):
135 self.close(int(self["number"].getText()))
137 def keyNumberGlobal(self, number):
138 self.Timer.start(3000, True) #reset timer
139 self.field = self.field + str(number)
140 self["number"].setText(self.field)
141 if len(self.field) >= 4:
144 def __init__(self, session, number):
145 Screen.__init__(self, session)
146 self.field = str(number)
148 self["channel"] = Label(_("Channel:"))
150 self["number"] = Label(self.field)
152 self["actions"] = NumberActionMap( [ "SetupActions" ],
156 "1": self.keyNumberGlobal,
157 "2": self.keyNumberGlobal,
158 "3": self.keyNumberGlobal,
159 "4": self.keyNumberGlobal,
160 "5": self.keyNumberGlobal,
161 "6": self.keyNumberGlobal,
162 "7": self.keyNumberGlobal,
163 "8": self.keyNumberGlobal,
164 "9": self.keyNumberGlobal,
165 "0": self.keyNumberGlobal
168 self.Timer = eTimer()
169 self.Timer.timeout.get().append(self.keyOK)
170 self.Timer.start(3000, True)
172 class InfoBarNumberZap:
173 """ Handles an initial number for NumberZapping """
175 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
177 "1": self.keyNumberGlobal,
178 "2": self.keyNumberGlobal,
179 "3": self.keyNumberGlobal,
180 "4": self.keyNumberGlobal,
181 "5": self.keyNumberGlobal,
182 "6": self.keyNumberGlobal,
183 "7": self.keyNumberGlobal,
184 "8": self.keyNumberGlobal,
185 "9": self.keyNumberGlobal,
186 "0": self.keyNumberGlobal,
189 def keyNumberGlobal(self, number):
190 # print "You pressed number " + str(number)
192 self.servicelist.recallPrevService()
195 self.session.openWithCallback(self.numberEntered, NumberZap, number)
197 def numberEntered(self, retval):
198 # print self.servicelist
200 self.zapToNumber(retval)
202 def searchNumberHelper(self, serviceHandler, num, bouquet):
203 servicelist = serviceHandler.list(bouquet)
204 if not servicelist is None:
206 serviceIterator = servicelist.getNext()
207 if not serviceIterator.valid(): #check end of list
209 if serviceIterator.flags: #assume normal dvb service have no flags set
212 if not num: #found service with searched number ?
213 return serviceIterator, 0
216 def zapToNumber(self, number):
217 bouquet = self.servicelist.bouquet_root
219 serviceHandler = eServiceCenter.getInstance()
220 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
221 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
223 bouquetlist = serviceHandler.list(bouquet)
224 if not bouquetlist is None:
226 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
227 if not bouquet.valid(): #check end of list
229 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
231 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
232 if not service is None:
233 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
234 self.servicelist.clearPath()
235 if self.servicelist.bouquet_root != bouquet:
236 self.servicelist.enterPath(self.servicelist.bouquet_root)
237 self.servicelist.enterPath(bouquet)
238 self.servicelist.setCurrentSelection(service) #select the service in servicelist
239 self.servicelist.zap()
241 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
243 class InfoBarChannelSelection:
244 """ ChannelSelection - handles the channelSelection dialog and the initial
245 channelChange actions which open the channelSelection dialog """
248 self.servicelist = self.session.instantiateDialog(ChannelSelection)
250 if config.misc.initialchannelselection.value == 1:
251 self.onShown.append(self.firstRun)
253 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
255 "switchChannelUp": self.switchChannelUp,
256 "switchChannelDown": self.switchChannelDown,
257 "zapUp": (self.zapUp, _("previous channel")),
258 "zapDown": (self.zapDown, _("next channel")),
259 "historyBack": (self.historyBack, _("previous channel in history")),
260 "historyNext": (self.historyNext, _("next channel in history"))
264 self.onShown.remove(self.firstRun)
265 config.misc.initialchannelselection.value = 0
266 config.misc.initialchannelselection.save()
267 self.switchChannelDown()
269 def historyBack(self):
270 self.servicelist.historyBack()
272 def historyNext(self):
273 self.servicelist.historyNext()
275 def switchChannelUp(self):
276 self.servicelist.moveUp()
277 self.session.execDialog(self.servicelist)
279 def switchChannelDown(self):
280 self.servicelist.moveDown()
281 self.session.execDialog(self.servicelist)
284 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
285 if self.servicelist.inBouquet() and self.servicelist.atBegin():
286 self.servicelist.prevBouquet()
287 self.servicelist.moveUp()
288 self.servicelist.zap()
292 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
293 self.servicelist.nextBouquet()
295 self.servicelist.moveDown()
296 self.servicelist.zap()
300 """ Handles a menu action, to open the (main) menu """
302 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
304 "mainMenu": (self.mainMenu, "Enter main menu..."),
308 print "loading mainmenu XML..."
309 menu = mdom.childNodes[0]
310 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
311 self.session.open(MainMenu, menu, menu.childNodes)
313 class InfoBarSimpleEventView:
314 """ Opens the Eventview for now/next """
316 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
318 "showEventInfo": (self.openEventView, _("show event details")),
321 def openEventView(self):
323 service = self.session.nav.getCurrentService()
324 ref = self.session.nav.getCurrentlyPlayingServiceReference()
325 info = service.info()
328 self.epglist.append(ptr)
331 self.epglist.append(ptr)
332 if len(self.epglist) > 0:
333 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
335 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
336 if len(self.epglist) > 1:
337 tmp = self.epglist[0]
338 self.epglist[0]=self.epglist[1]
340 setEvent(self.epglist[0])
343 """ EPG - Opens an EPG list when the showEPGList action fires """
345 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
347 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
350 self.is_now_next = False
352 self.bouquetSel = None
353 self.eventView = None
354 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
356 "showEventInfo": (self.openEventView, _("show EPG...")),
359 def zapToService(self, service):
360 if not service is None:
361 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
362 self.servicelist.clearPath()
363 if self.servicelist.bouquet_root != self.epg_bouquet:
364 self.servicelist.enterPath(self.servicelist.bouquet_root)
365 self.servicelist.enterPath(self.epg_bouquet)
366 self.servicelist.setCurrentSelection(service) #select the service in servicelist
367 self.servicelist.zap()
369 def getBouquetServices(self, bouquet):
371 servicelist = eServiceCenter.getInstance().list(bouquet)
372 if not servicelist is None:
374 service = servicelist.getNext()
375 if not service.valid(): #check if end of list
377 if service.flags: #ignore non playable services
379 services.append(ServiceReference(service))
382 def openBouquetEPG(self, bouquet, withCallback=True):
383 services = self.getBouquetServices(bouquet)
385 self.epg_bouquet = bouquet
387 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
389 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
391 def changeBouquetCB(self, direction, epg):
394 self.bouquetSel.down()
397 bouquet = self.bouquetSel.getCurrent()
398 services = self.getBouquetServices(bouquet)
400 self.epg_bouquet = bouquet
401 epg.setServices(services)
403 def closed(self, ret=False):
404 closedScreen = self.dlg_stack.pop()
405 if self.bouquetSel and closedScreen == self.bouquetSel:
406 self.bouquetSel = None
407 elif self.eventView and closedScreen == self.eventView:
408 self.eventView = None
410 dlgs=len(self.dlg_stack)
412 self.dlg_stack[dlgs-1].close(dlgs > 1)
414 def openMultiServiceEPG(self, withCallback=True):
415 bouquets = self.servicelist.getBouquetList()
420 if cnt > 1: # show bouquet list
422 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
423 self.dlg_stack.append(self.bouquetSel)
425 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
427 self.openBouquetEPG(bouquets[0][1], withCallback)
429 def openSingleServiceEPG(self):
430 ref=self.session.nav.getCurrentlyPlayingServiceReference()
431 self.session.open(EPGSelection, ref)
433 def openSimilarList(self, eventid, refstr):
434 self.session.open(EPGSelection, refstr, None, eventid)
436 def getNowNext(self):
438 service = self.session.nav.getCurrentService()
439 info = service and service.info()
440 ptr = info and info.getEvent(0)
442 self.epglist.append(ptr)
443 ptr = info and info.getEvent(1)
445 self.epglist.append(ptr)
447 def __evEventInfoChanged(self):
448 if self.is_now_next and len(self.dlg_stack) == 1:
450 assert self.eventView
451 if len(self.epglist):
452 self.eventView.setEvent(self.epglist[0])
454 def openEventView(self):
455 ref = self.session.nav.getCurrentlyPlayingServiceReference()
457 if len(self.epglist) == 0:
458 self.is_now_next = False
459 epg = eEPGCache.getInstance()
460 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
462 self.epglist.append(ptr)
463 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
465 self.epglist.append(ptr)
467 self.is_now_next = True
468 if len(self.epglist) > 0:
469 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
470 self.dlg_stack.append(self.eventView)
472 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
473 self.openMultiServiceEPG(False)
475 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
476 if len(self.epglist) > 1:
477 tmp = self.epglist[0]
478 self.epglist[0]=self.epglist[1]
480 setEvent(self.epglist[0])
483 """provides a snr/agc/ber display"""
485 self["snr"] = Label()
486 self["agc"] = Label()
487 self["ber"] = Label()
488 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
489 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
490 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
491 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
492 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
493 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
494 self.timer = eTimer()
495 self.timer.timeout.get().append(self.updateTunerInfo)
496 self.timer.start(1000)
498 def updateTunerInfo(self):
499 if self.instance.isVisible():
500 self["snr_percent"].update()
501 self["agc_percent"].update()
502 self["ber_count"].update()
503 self["snr_progress"].update()
504 self["agc_progress"].update()
505 self["ber_progress"].update()
508 """provides a current/next event info display"""
510 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
511 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
513 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
514 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
516 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
517 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
519 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
521 class InfoBarServiceName:
523 self["ServiceName"] = ServiceName(self.session.nav)
526 """handles actions like seeking, pause"""
528 # ispause, isff, issm
529 SEEK_STATE_PLAY = (0, 0, 0, ">")
530 SEEK_STATE_PAUSE = (1, 0, 0, "||")
531 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
532 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
533 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
534 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
535 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
536 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
538 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
539 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
540 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
541 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
543 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
544 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
545 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
548 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
550 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
551 iPlayableService.evStart: self.__serviceStarted,
553 iPlayableService.evEOF: self.__evEOF,
554 iPlayableService.evSOF: self.__evSOF,
557 class InfoBarSeekActionMap(HelpableActionMap):
558 def __init__(self, screen, *args, **kwargs):
559 HelpableActionMap.__init__(self, screen, *args, **kwargs)
562 def action(self, contexts, action):
563 if action[:5] == "seek:":
564 time = int(action[5:])
565 self.screen.seekRelative(time * 90000)
568 return HelpableActionMap.action(self, contexts, action)
570 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
572 "pauseService": (self.pauseService, "pause"),
573 "unPauseService": (self.unPauseService, "continue"),
575 "seekFwd": (self.seekFwd, "skip forward"),
576 "seekFwdDown": self.seekFwdDown,
577 "seekFwdUp": self.seekFwdUp,
578 "seekBack": (self.seekBack, "skip backward"),
579 "seekBackDown": self.seekBackDown,
580 "seekBackUp": self.seekBackUp,
582 # give them a little more priority to win over color buttons
584 self.seekstate = self.SEEK_STATE_PLAY
585 self.onClose.append(self.delTimer)
587 self.fwdtimer = False
588 self.fwdKeyTimer = eTimer()
589 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
591 self.rwdtimer = False
592 self.rwdKeyTimer = eTimer()
593 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
595 self.onPlayStateChanged = [ ]
597 self.lockedBecauseOfSkipping = False
610 service = self.session.nav.getCurrentService()
614 seek = service.seek()
616 if seek is None or not seek.isCurrentlySeekable():
621 def isSeekable(self):
622 if self.getSeek() is None:
626 def __seekableStatusChanged(self):
627 print "seekable status changed!"
628 if not self.isSeekable():
629 self["SeekActions"].setEnabled(False)
630 print "not seekable, return to play"
631 self.setSeekState(self.SEEK_STATE_PLAY)
633 self["SeekActions"].setEnabled(True)
636 def __serviceStarted(self):
637 self.seekstate = self.SEEK_STATE_PLAY
639 def setSeekState(self, state):
640 service = self.session.nav.getCurrentService()
645 if not self.isSeekable():
646 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
647 state = self.SEEK_STATE_PLAY
649 pauseable = service.pause()
651 if pauseable is None:
652 print "not pauseable."
653 state = self.SEEK_STATE_PLAY
655 oldstate = self.seekstate
656 self.seekstate = state
659 if oldstate[i] != self.seekstate[i]:
660 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
662 for c in self.onPlayStateChanged:
665 self.checkSkipShowHideLock()
669 def pauseService(self):
670 if self.seekstate == self.SEEK_STATE_PAUSE:
671 print "pause, but in fact unpause"
672 self.unPauseService()
674 if self.seekstate == self.SEEK_STATE_PLAY:
675 print "yes, playing."
677 print "no", self.seekstate
679 self.setSeekState(self.SEEK_STATE_PAUSE);
681 def unPauseService(self):
683 self.setSeekState(self.SEEK_STATE_PLAY);
685 def doSeek(self, seektime):
686 print "doseek", seektime
687 service = self.session.nav.getCurrentService()
691 seekable = self.getSeek()
695 seekable.seekTo(90 * seektime)
697 def seekFwdDown(self):
698 print "start fwd timer"
700 self.fwdKeyTimer.start(1000)
702 def seekBackDown(self):
703 print "start rewind timer"
705 self.rwdKeyTimer.start(1000)
710 self.fwdKeyTimer.stop()
711 self.fwdtimer = False
716 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
717 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
718 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
719 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
720 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
721 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
722 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
723 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
724 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
725 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
726 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
727 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
728 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
729 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
730 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
732 self.setSeekState(lookup[self.seekstate])
734 def seekBackUp(self):
737 self.rwdKeyTimer.stop()
738 self.rwdtimer = False
743 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
744 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
745 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
746 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
747 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
748 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
749 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
750 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
751 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
752 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
753 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
754 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
755 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
756 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
757 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
759 self.setSeekState(lookup[self.seekstate])
761 if self.seekstate == self.SEEK_STATE_PAUSE:
762 seekable = self.getSeek()
763 if seekable is not None:
764 seekable.seekRelative(-1, 3)
766 def fwdTimerFire(self):
767 print "Display seek fwd"
768 self.fwdKeyTimer.stop()
769 self.fwdtimer = False
770 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
772 def fwdSeekTo(self, minutes):
773 print "Seek", minutes, "minutes forward"
775 seekable = self.getSeek()
776 if seekable is not None:
777 seekable.seekRelative(1, minutes * 60 * 90000)
779 def rwdTimerFire(self):
781 self.rwdKeyTimer.stop()
782 self.rwdtimer = False
783 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
785 def rwdSeekTo(self, minutes):
787 self.fwdSeekTo(0 - minutes)
789 def checkSkipShowHideLock(self):
790 wantlock = self.seekstate != self.SEEK_STATE_PLAY
792 if self.lockedBecauseOfSkipping and not wantlock:
794 self.lockedBecauseOfSkipping = False
796 if wantlock and not self.lockedBecauseOfSkipping:
798 self.lockedBecauseOfSkipping = True
801 if self.seekstate != self.SEEK_STATE_PLAY:
802 self.setSeekState(self.SEEK_STATE_PAUSE)
804 #self.getSeek().seekRelative(1, -90000)
805 self.setSeekState(self.SEEK_STATE_PLAY)
807 self.setSeekState(self.SEEK_STATE_PAUSE)
810 self.setSeekState(self.SEEK_STATE_PLAY)
813 def seekRelative(self, diff):
814 seekable = self.getSeek()
815 if seekable is not None:
816 seekable.seekRelative(1, diff)
818 from Screens.PVRState import PVRState, TimeshiftState
820 class InfoBarPVRState:
821 def __init__(self, screen=PVRState):
822 self.onPlayStateChanged.append(self.__playStateChanged)
823 self.pvrStateDialog = self.session.instantiateDialog(screen)
824 self.onShow.append(self.__mayShow)
825 self.onHide.append(self.pvrStateDialog.hide)
828 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
829 self.pvrStateDialog.show()
831 def __playStateChanged(self, state):
832 playstateString = state[3]
833 self.pvrStateDialog["state"].setText(playstateString)
836 class InfoBarTimeshiftState(InfoBarPVRState):
838 InfoBarPVRState.__init__(self, screen=TimeshiftState)
841 class InfoBarShowMovies:
843 # i don't really like this class.
844 # it calls a not further specified "movie list" on up/down/movieList,
845 # so this is not more than an action map
847 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
849 "movieList": (self.showMovies, "movie list"),
850 "up": (self.showMovies, "movie list"),
851 "down": (self.showMovies, "movie list")
854 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
858 # Timeshift works the following way:
859 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
860 # - normal playback TUNER unused PLAY enable disable disable
861 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
862 # - user presess pause again FILE record PLAY enable disable enable
863 # - user fast forwards FILE record FF enable disable enable
864 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
865 # - user backwards FILE record BACK # !! enable disable enable
869 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
870 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
871 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
872 # - the user can now PVR around
873 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
874 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
876 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
877 # - if the user rewinds, or press pause, timeshift will be activated again
879 # note that a timeshift can be enabled ("recording") and
880 # activated (currently time-shifting).
882 class InfoBarTimeshift:
884 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
886 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
887 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
889 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
891 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
892 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
893 }, prio=-1) # priority over record
895 self.timeshift_enabled = 0
896 self.timeshift_state = 0
897 self.ts_pause_timer = eTimer()
898 self.ts_pause_timer.timeout.get().append(self.pauseService)
900 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
902 iPlayableService.evStart: self.__serviceStarted,
903 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
906 def getTimeshift(self):
907 service = self.session.nav.getCurrentService()
908 return service and service.timeshift()
910 def startTimeshift(self):
911 print "enable timeshift"
912 ts = self.getTimeshift()
914 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
915 print "no ts interface"
918 if self.timeshift_enabled:
919 print "hu, timeshift already enabled?"
921 if not ts.startTimeshift():
923 self.timeshift_enabled = 1
924 self.pvrStateDialog["timeshift"].setRelative(time.time())
927 self.setSeekState(self.SEEK_STATE_PAUSE)
929 # enable the "TimeshiftEnableActions", which will override
930 # the startTimeshift actions
931 self.__seekableStatusChanged()
933 print "timeshift failed"
935 def stopTimeshift(self):
936 if not self.timeshift_enabled:
938 print "disable timeshift"
939 ts = self.getTimeshift()
942 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
944 def stopTimeshiftConfirmed(self, confirmed):
948 ts = self.getTimeshift()
953 self.timeshift_enabled = 0
956 self.__seekableStatusChanged()
958 # activates timeshift, and seeks to (almost) the end
959 def activateTimeshiftEnd(self):
960 ts = self.getTimeshift()
965 if ts.isTimeshiftActive():
966 print "!! activate timeshift called - but shouldn't this be a normal pause?"
969 self.setSeekState(self.SEEK_STATE_PLAY)
970 ts.activateTimeshift()
973 # same as activateTimeshiftEnd, but pauses afterwards.
974 def activateTimeshiftEndAndPause(self):
975 state = self.seekstate
976 self.activateTimeshiftEnd()
978 # well, this is "andPause", but it could be pressed from pause,
979 # when pausing on the (fake-)"live" picture, so an un-pause
982 print "now, pauseService"
983 if state == self.SEEK_STATE_PLAY:
984 print "is PLAYING, start pause timer"
985 self.ts_pause_timer.start(200, 1)
988 self.unPauseService()
990 def __seekableStatusChanged(self):
993 print "self.isSeekable", self.isSeekable()
994 print "self.timeshift_enabled", self.timeshift_enabled
996 # when this service is not seekable, but timeshift
997 # is enabled, this means we can activate
999 if not self.isSeekable() and self.timeshift_enabled:
1002 print "timeshift activate:", enabled
1003 self["TimeshiftActivateActions"].setEnabled(enabled)
1005 def __serviceStarted(self):
1006 self.timeshift_enabled = False
1007 self.__seekableStatusChanged()
1009 from Screens.PiPSetup import PiPSetup
1011 class InfoBarExtensions:
1013 self.pipshown = False
1015 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1017 "extensions": (self.extensions, "Extensions..."),
1024 def extensions(self):
1026 if self.pipshown == False:
1027 list.append((_("Activate Picture in Picture"), self.PIPON))
1028 elif self.pipshown == True:
1029 list.append((_("Disable Picture in Picture"), self.PIPOFF))
1030 list.append((_("Move Picture in Picture"), self.MOVEPIP))
1031 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
1033 def extensionCallback(self, answer):
1034 if answer is not None:
1035 if answer[1] == self.PIPON:
1036 # self.session.nav.stopService()
1037 self.pip = self.session.instantiateDialog(PictureInPicture)
1040 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1041 self.pipservice = eServiceCenter.getInstance().play(newservice)
1042 if self.pipservice and not self.pipservice.setTarget(1):
1043 self.pipservice.start()
1044 self.pipshown = True
1046 self.pipservice = None
1048 self.session.nav.playService(newservice)
1049 elif answer[1] == self.PIPOFF:
1051 self.pipservice = None
1053 self.pipshown = False
1054 elif answer[1] == self.MOVEPIP:
1055 self.session.open(PiPSetup, pip = self.pip)
1057 from RecordTimer import parseEvent
1059 class InfoBarInstantRecord:
1060 """Instant Record - handles the instantRecord action in order to
1061 start/stop instant records"""
1063 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1065 "instantRecord": (self.instantRecord, "Instant Record..."),
1068 self["BlinkingPoint"] = BlinkingPixmapConditional()
1069 self["BlinkingPoint"].hide()
1070 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1072 def stopCurrentRecording(self, entry = -1):
1073 if entry is not None and entry != -1:
1074 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1075 self.recording.remove(self.recording[entry])
1077 def startInstantRecording(self, limitEvent = False):
1078 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1080 # try to get event info
1083 service = self.session.nav.getCurrentService()
1084 epg = eEPGCache.getInstance()
1085 event = epg.lookupEventTime(serviceref, -1, 0)
1087 info = service.info()
1088 ev = info.getEvent(0)
1094 end = time.time() + 3600 * 10
1095 name = "instant record"
1099 if event is not None:
1100 curEvent = parseEvent(event)
1102 description = curEvent[3]
1103 eventid = curEvent[4]
1108 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1110 data = (begin, end, name, description, eventid)
1112 recording = self.session.nav.recordWithTimer(serviceref, *data)
1113 recording.dontSave = True
1114 self.recording.append(recording)
1116 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1118 def isInstantRecordRunning(self):
1119 print "self.recording:", self.recording
1120 if len(self.recording) > 0:
1121 for x in self.recording:
1126 def recordQuestionCallback(self, answer):
1127 print "pre:\n", self.recording
1129 if answer is None or answer[1] == "no":
1132 recording = self.recording[:]
1134 if not x in self.session.nav.RecordTimer.timer_list:
1135 self.recording.remove(x)
1136 elif x.dontSave and x.isRunning():
1137 list.append(TimerEntryComponent(x, False))
1139 if answer[1] == "changeduration":
1140 if len(self.recording) == 1:
1141 self.changeDuration(0)
1143 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1144 elif answer[1] == "stop":
1145 if len(self.recording) == 1:
1146 self.stopCurrentRecording(0)
1148 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1149 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1151 if answer[1] == "event":
1153 if answer[1] == "manualduration":
1154 self.selectedEntry = len(self.recording)
1155 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1156 self.startInstantRecording(limitEvent = limitEvent)
1158 print "after:\n", self.recording
1160 def changeDuration(self, entry):
1161 if entry is not None:
1162 self.selectedEntry = entry
1163 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1165 def inputCallback(self, value):
1166 if value is not None:
1167 print "stopping recording after", int(value), "minutes."
1168 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1169 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1171 def instantRecord(self):
1173 stat = os.stat(resolveFilename(SCOPE_HDD))
1175 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1178 if self.isInstantRecordRunning():
1179 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")])
1181 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")])
1183 from Tools.ISO639 import LanguageCodes
1185 class InfoBarAudioSelection:
1187 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1189 "audioSelection": (self.audioSelection, "Audio Options..."),
1192 def audioSelection(self):
1193 service = self.session.nav.getCurrentService()
1194 audio = service.audioTracks()
1195 self.audioTracks = audio
1196 n = audio.getNumberOfTracks()
1198 # self.audioChannel = service.audioChannel()
1199 # config.audio.audiochannel = configElement_nonSave("config.audio.audiochannel", configSelection, self.audioChannel.getCurrentChannel(), (("left", _("Left >")), ("stereo", _("< Stereo >")), ("right", _("< Right"))))
1202 i = audio.getTrackInfo(x)
1203 language = i.getLanguage()
1204 description = i.getDescription();
1206 if len(language) == 3:
1207 if language in LanguageCodes:
1208 language = LanguageCodes[language][0]
1210 if len(description):
1211 description += " (" + language + ")"
1213 description = language
1215 tlist.append((description, x))
1217 selectedAudio = tlist[0][1]
1218 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1220 # tlist.insert(0, getConfigListEntry(_("Audio Channel"), config.audio.audiochannel))
1224 if x[1] != selectedAudio:
1229 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection)
1231 del self.audioTracks
1233 def audioSelected(self, audio):
1234 if audio is not None:
1235 self.audioTracks.selectTrack(audio[1])
1236 del self.audioTracks
1237 # del self.audioChannel
1238 # del config.audio.audiochannel
1240 class InfoBarSubserviceSelection:
1242 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1244 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1247 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1249 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1250 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1252 self["SubserviceQuickzapAction"].setEnabled(False)
1254 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1256 def checkSubservicesAvail(self, ev):
1257 if ev == iPlayableService.evUpdatedEventInfo:
1258 service = self.session.nav.getCurrentService()
1259 subservices = service.subServices()
1260 if subservices.getNumberOfSubservices() == 0:
1261 self["SubserviceQuickzapAction"].setEnabled(False)
1263 def nextSubservice(self):
1264 self.changeSubservice(+1)
1266 def prevSubservice(self):
1267 self.changeSubservice(-1)
1269 def changeSubservice(self, direction):
1270 service = self.session.nav.getCurrentService()
1271 subservices = service.subServices()
1272 n = subservices.getNumberOfSubservices()
1275 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1277 if subservices.getSubservice(x).toString() == ref.toString():
1280 selection += direction
1285 newservice = subservices.getSubservice(selection)
1286 if newservice.valid():
1289 self.session.nav.playService(newservice)
1291 def subserviceSelection(self):
1292 service = self.session.nav.getCurrentService()
1293 subservices = service.subServices()
1295 n = subservices.getNumberOfSubservices()
1298 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1301 i = subservices.getSubservice(x)
1302 if i.toString() == ref.toString():
1304 tlist.append((i.getName(), i))
1306 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection)
1308 def subserviceSelected(self, service):
1309 if not service is None:
1310 self["SubserviceQuickzapAction"].setEnabled(True)
1311 self.session.nav.playService(service[1])
1313 class InfoBarAdditionalInfo:
1315 self["DolbyActive"] = Pixmap()
1316 self["CryptActive"] = Pixmap()
1317 self["FormatActive"] = Pixmap()
1319 self["ButtonRed"] = PixmapConditional(withTimer = False)
1320 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1321 self.onLayoutFinish.append(self["ButtonRed"].update)
1322 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1323 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1324 self.onLayoutFinish.append(self["ButtonRedText"].update)
1326 self["ButtonGreen"] = Pixmap()
1327 self["ButtonGreenText"] = Label(_("Subservices"))
1329 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1330 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1331 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1332 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1333 self.onLayoutFinish.append(self["ButtonYellow"].update)
1334 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1336 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1337 self["ButtonBlue"].setConnect(lambda: True)
1338 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1339 self["ButtonBlueText"].setConnect(lambda: True)
1340 self.onLayoutFinish.append(self["ButtonBlue"].update)
1341 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1343 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1345 def hideSubServiceIndication(self):
1346 self["ButtonGreen"].hide()
1347 self["ButtonGreenText"].hide()
1349 def showSubServiceIndication(self):
1350 self["ButtonGreen"].show()
1351 self["ButtonGreenText"].show()
1353 def checkFormat(self, service):
1354 info = service.info()
1355 if info is not None:
1356 aspect = info.getInfo(iServiceInformation.sAspect)
1357 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1358 self["FormatActive"].show()
1360 self["FormatActive"].hide()
1362 def checkSubservices(self, service):
1363 if service.subServices().getNumberOfSubservices() > 0:
1364 self.showSubServiceIndication()
1366 self.hideSubServiceIndication()
1368 def checkDolby(self, service):
1371 audio = service.audioTracks()
1372 if audio is not None:
1373 n = audio.getNumberOfTracks()
1375 i = audio.getTrackInfo(x)
1376 description = i.getDescription();
1377 if description.find("AC3") != -1 or description.find("DTS") != -1:
1381 self["DolbyActive"].show()
1383 self["DolbyActive"].hide()
1385 def checkCrypted(self, service):
1386 info = service.info()
1387 if info is not None:
1388 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1389 self["CryptActive"].show()
1391 self["CryptActive"].hide()
1393 def gotServiceEvent(self, ev):
1394 service = self.session.nav.getCurrentService()
1395 if ev == iPlayableService.evUpdatedEventInfo:
1396 self.checkSubservices(service)
1397 self.checkFormat(service)
1398 elif ev == iPlayableService.evUpdatedInfo:
1399 self.checkCrypted(service)
1400 self.checkDolby(service)
1401 elif ev == iPlayableService.evEnd:
1402 self.hideSubServiceIndication()
1403 self["CryptActive"].hide()
1404 self["DolbyActive"].hide()
1405 self["FormatActive"].hide()
1407 class InfoBarNotifications:
1409 self.onExecBegin.append(self.checkNotifications)
1410 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1412 def checkNotificationsIfExecing(self):
1414 self.checkNotifications()
1416 def checkNotifications(self):
1417 if len(Notifications.notifications):
1418 n = Notifications.notifications[0]
1419 Notifications.notifications = Notifications.notifications[1:]
1423 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1425 self.session.open(n[1], *n[2], **n[3])
1427 class InfoBarServiceNotifications:
1429 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1431 iPlayableService.evEnd: self.serviceHasEnded
1434 def serviceHasEnded(self):
1435 print "service end!"
1438 self.setSeekState(self.SEEK_STATE_PLAY)
1442 class InfoBarCueSheetSupport:
1448 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1450 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1451 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1452 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1456 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1458 iPlayableService.evStart: self.__serviceStarted,
1461 def __serviceStarted(self):
1462 print "new service started! trying to download cuts!"
1463 self.downloadCuesheet()
1465 def __getSeekable(self):
1466 service = self.session.nav.getCurrentService()
1469 return service.seek()
1471 def cueGetCurrentPosition(self):
1472 seek = self.__getSeekable()
1475 r = seek.getPlayPosition()
1480 def jumpPreviousNextMark(self, cmp, alternative=None):
1481 current_pos = self.cueGetCurrentPosition()
1482 if current_pos is None:
1484 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1485 if mark is not None:
1487 elif alternative is not None:
1492 seekable = self.__getSeekable()
1493 if seekable is not None:
1494 seekable.seekTo(pts)
1496 def jumpPreviousMark(self):
1497 # we add 2 seconds, so if the play position is <2s after
1498 # the mark, the mark before will be used
1499 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1501 def jumpNextMark(self):
1502 self.jumpPreviousNextMark(lambda x: x)
1504 def getNearestCutPoint(self, pts, cmp=abs):
1507 for cp in self.cut_list:
1508 diff = cmp(cp[0] - pts)
1509 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1513 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1514 current_pos = self.cueGetCurrentPosition()
1515 if current_pos is None:
1516 print "not seekable"
1519 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1521 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1523 return nearest_cutpoint
1525 self.removeMark(nearest_cutpoint)
1526 elif not onlyremove and not onlyreturn:
1527 self.addMark((current_pos, self.CUT_TYPE_MARK))
1532 def addMark(self, point):
1533 bisect.insort(self.cut_list, point)
1534 self.uploadCuesheet()
1536 def removeMark(self, point):
1537 self.cut_list.remove(point)
1538 self.uploadCuesheet()
1540 def __getCuesheet(self):
1541 service = self.session.nav.getCurrentService()
1544 return service.cueSheet()
1546 def uploadCuesheet(self):
1547 cue = self.__getCuesheet()
1550 print "upload failed, no cuesheet interface"
1552 cue.setCutList(self.cut_list)
1554 def downloadCuesheet(self):
1555 cue = self.__getCuesheet()
1558 print "upload failed, no cuesheet interface"
1560 self.cut_list = cue.getCutList()
1562 class InfoBarSummary(Screen):
1564 <screen position="0,0" size="132,64">
1565 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1566 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1569 def __init__(self, session, parent):
1570 Screen.__init__(self, session)
1571 self["CurrentService"] = ServiceName(self.session.nav)
1572 self["Clock"] = Clock()
1574 class InfoBarSummarySupport:
1578 def createSummary(self):
1579 return InfoBarSummary
1581 class InfoBarTeletextPlugin:
1583 self.teletext_plugin = None
1585 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1586 self.teletext_plugin = p
1588 if self.teletext_plugin is not None:
1589 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1591 "startTeletext": (self.startTeletext, "View teletext...")
1594 print "no teletext plugin found!"
1596 def startTeletext(self):
1597 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())