1 from ChannelSelection import ChannelSelection, BouquetSelector
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.FrontendStatus import FrontendStatus
16 from Components.Sources.Boolean import Boolean
17 from Components.Sources.Clock import Clock
18 from Components.TimerList import TimerEntryComponent
19 from Components.config import config, configElement, ConfigSubsection, configSequence, configElementBoolean, configSelection, configElement_nonSave, getConfigListEntry
20 from Components.config import configfile, configsequencearg
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from ServiceReference import ServiceReference
37 from Tools import Notifications
38 from Tools.Directories import *
40 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
47 from Components.config import config, currentConfigSelectionElement
50 from Menu import MainMenu, mdom
54 self.dishDialog = self.session.instantiateDialog(Dish)
55 self.onLayoutFinish.append(self.dishDialog.show)
57 class InfoBarShowHide:
58 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
66 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
68 "toggleShow": self.toggleShow,
72 self.__state = self.STATE_SHOWN
75 self.onExecBegin.append(self.show)
77 self.hideTimer = eTimer()
78 self.hideTimer.timeout.get().append(self.doTimerHide)
79 self.hideTimer.start(5000, True)
81 self.onShow.append(self.__onShow)
82 self.onHide.append(self.__onHide)
85 self.__state = self.STATE_SHOWN
88 def startHideTimer(self):
89 if self.__state == self.STATE_SHOWN and not self.__locked:
90 self.hideTimer.start(5000, True)
93 self.__state = self.STATE_HIDDEN
99 def doTimerHide(self):
100 self.hideTimer.stop()
101 if self.__state == self.STATE_SHOWN:
104 def toggleShow(self):
105 if self.__state == self.STATE_SHOWN:
107 self.hideTimer.stop()
108 elif self.__state == self.STATE_HIDDEN:
112 self.__locked = self.__locked + 1
115 self.hideTimer.stop()
117 def unlockShow(self):
118 self.__locked = self.__locked - 1
120 self.startHideTimer()
122 # def startShow(self):
123 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
124 # self.__state = self.STATE_SHOWN
126 # def startHide(self):
127 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
128 # self.__state = self.STATE_HIDDEN
130 class NumberZap(Screen):
137 self.close(int(self["number"].getText()))
139 def keyNumberGlobal(self, number):
140 self.Timer.start(3000, True) #reset timer
141 self.field = self.field + str(number)
142 self["number"].setText(self.field)
143 if len(self.field) >= 4:
146 def __init__(self, session, number):
147 Screen.__init__(self, session)
148 self.field = str(number)
150 self["channel"] = Label(_("Channel:"))
152 self["number"] = Label(self.field)
154 self["actions"] = NumberActionMap( [ "SetupActions" ],
158 "1": self.keyNumberGlobal,
159 "2": self.keyNumberGlobal,
160 "3": self.keyNumberGlobal,
161 "4": self.keyNumberGlobal,
162 "5": self.keyNumberGlobal,
163 "6": self.keyNumberGlobal,
164 "7": self.keyNumberGlobal,
165 "8": self.keyNumberGlobal,
166 "9": self.keyNumberGlobal,
167 "0": self.keyNumberGlobal
170 self.Timer = eTimer()
171 self.Timer.timeout.get().append(self.keyOK)
172 self.Timer.start(3000, True)
174 class InfoBarNumberZap:
175 """ Handles an initial number for NumberZapping """
177 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
179 "1": self.keyNumberGlobal,
180 "2": self.keyNumberGlobal,
181 "3": self.keyNumberGlobal,
182 "4": self.keyNumberGlobal,
183 "5": self.keyNumberGlobal,
184 "6": self.keyNumberGlobal,
185 "7": self.keyNumberGlobal,
186 "8": self.keyNumberGlobal,
187 "9": self.keyNumberGlobal,
188 "0": self.keyNumberGlobal,
191 def keyNumberGlobal(self, number):
192 # print "You pressed number " + str(number)
194 self.servicelist.recallPrevService()
197 self.session.openWithCallback(self.numberEntered, NumberZap, number)
199 def numberEntered(self, retval):
200 # print self.servicelist
202 self.zapToNumber(retval)
204 def searchNumberHelper(self, serviceHandler, num, bouquet):
205 servicelist = serviceHandler.list(bouquet)
206 if not servicelist is None:
208 serviceIterator = servicelist.getNext()
209 if not serviceIterator.valid(): #check end of list
211 if serviceIterator.flags: #assume normal dvb service have no flags set
214 if not num: #found service with searched number ?
215 return serviceIterator, 0
218 def zapToNumber(self, number):
219 bouquet = self.servicelist.bouquet_root
221 serviceHandler = eServiceCenter.getInstance()
222 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
223 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
225 bouquetlist = serviceHandler.list(bouquet)
226 if not bouquetlist is None:
228 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
229 if not bouquet.valid(): #check end of list
231 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
233 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
234 if not service is None:
235 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
236 self.servicelist.clearPath()
237 if self.servicelist.bouquet_root != bouquet:
238 self.servicelist.enterPath(self.servicelist.bouquet_root)
239 self.servicelist.enterPath(bouquet)
240 self.servicelist.setCurrentSelection(service) #select the service in servicelist
241 self.servicelist.zap()
243 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
245 class InfoBarChannelSelection:
246 """ ChannelSelection - handles the channelSelection dialog and the initial
247 channelChange actions which open the channelSelection dialog """
250 self.servicelist = self.session.instantiateDialog(ChannelSelection)
252 if config.misc.initialchannelselection.value == 1:
253 self.onShown.append(self.firstRun)
255 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
257 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
258 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
259 "zapUp": (self.zapUp, _("previous channel")),
260 "zapDown": (self.zapDown, _("next channel")),
261 "historyBack": (self.historyBack, _("previous channel in history")),
262 "historyNext": (self.historyNext, _("next channel in history")),
263 "openServiceList": (self.openServiceList, _("open servicelist")),
266 def showTvChannelList(self, zap=False):
267 self.servicelist.setModeTv()
269 self.servicelist.zap()
270 self.session.execDialog(self.servicelist)
272 def showRadioChannelList(self, zap=False):
273 self.servicelist.setModeRadio()
275 self.servicelist.zap()
276 self.session.execDialog(self.servicelist)
279 self.onShown.remove(self.firstRun)
280 config.misc.initialchannelselection.value = 0
281 config.misc.initialchannelselection.save()
282 self.switchChannelDown()
284 def historyBack(self):
285 self.servicelist.historyBack()
287 def historyNext(self):
288 self.servicelist.historyNext()
290 def switchChannelUp(self):
291 self.servicelist.moveUp()
292 self.session.execDialog(self.servicelist)
294 def switchChannelDown(self):
295 self.servicelist.moveDown()
296 self.session.execDialog(self.servicelist)
298 def openServiceList(self):
299 self.session.execDialog(self.servicelist)
302 if self.servicelist.inBouquet():
303 prev = self.servicelist.getCurrentSelection()
305 prev = prev.toString()
307 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
308 if self.servicelist.atBegin():
309 self.servicelist.prevBouquet()
310 self.servicelist.moveUp()
311 cur = self.servicelist.getCurrentSelection()
312 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
315 self.servicelist.moveUp()
316 self.servicelist.zap()
320 if self.servicelist.inBouquet():
321 prev = self.servicelist.getCurrentSelection()
323 prev = prev.toString()
325 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.atEnd():
326 self.servicelist.nextBouquet()
328 self.servicelist.moveDown()
329 cur = self.servicelist.getCurrentSelection()
330 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
333 self.servicelist.moveDown()
334 self.servicelist.zap()
338 """ Handles a menu action, to open the (main) menu """
340 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
342 "mainMenu": (self.mainMenu, _("Enter main menu...")),
346 print "loading mainmenu XML..."
347 menu = mdom.childNodes[0]
348 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
349 self.session.open(MainMenu, menu, menu.childNodes)
351 class InfoBarSimpleEventView:
352 """ Opens the Eventview for now/next """
354 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
356 "showEventInfo": (self.openEventView, _("show event details")),
359 def openEventView(self):
361 service = self.session.nav.getCurrentService()
362 ref = self.session.nav.getCurrentlyPlayingServiceReference()
363 info = service.info()
366 self.epglist.append(ptr)
369 self.epglist.append(ptr)
370 if len(self.epglist) > 0:
371 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
373 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
374 if len(self.epglist) > 1:
375 tmp = self.epglist[0]
376 self.epglist[0]=self.epglist[1]
378 setEvent(self.epglist[0])
381 """ EPG - Opens an EPG list when the showEPGList action fires """
383 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
385 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
388 self.is_now_next = False
390 self.bouquetSel = None
391 self.eventView = None
392 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
394 "showEventInfo": (self.openEventView, _("show EPG...")),
397 def zapToService(self, service):
398 if not service is None:
399 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
400 self.servicelist.clearPath()
401 if self.servicelist.bouquet_root != self.epg_bouquet:
402 self.servicelist.enterPath(self.servicelist.bouquet_root)
403 self.servicelist.enterPath(self.epg_bouquet)
404 self.servicelist.setCurrentSelection(service) #select the service in servicelist
405 self.servicelist.zap()
407 def getBouquetServices(self, bouquet):
409 servicelist = eServiceCenter.getInstance().list(bouquet)
410 if not servicelist is None:
412 service = servicelist.getNext()
413 if not service.valid(): #check if end of list
415 if service.flags: #ignore non playable services
417 services.append(ServiceReference(service))
420 def openBouquetEPG(self, bouquet, withCallback=True):
421 services = self.getBouquetServices(bouquet)
423 self.epg_bouquet = bouquet
425 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
427 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
429 def changeBouquetCB(self, direction, epg):
432 self.bouquetSel.down()
435 bouquet = self.bouquetSel.getCurrent()
436 services = self.getBouquetServices(bouquet)
438 self.epg_bouquet = bouquet
439 epg.setServices(services)
441 def closed(self, ret=False):
442 closedScreen = self.dlg_stack.pop()
443 if self.bouquetSel and closedScreen == self.bouquetSel:
444 self.bouquetSel = None
445 elif self.eventView and closedScreen == self.eventView:
446 self.eventView = None
448 dlgs=len(self.dlg_stack)
450 self.dlg_stack[dlgs-1].close(dlgs > 1)
452 def openMultiServiceEPG(self, withCallback=True):
453 bouquets = self.servicelist.getBouquetList()
458 if cnt > 1: # show bouquet list
460 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
461 self.dlg_stack.append(self.bouquetSel)
463 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
465 self.openBouquetEPG(bouquets[0][1], withCallback)
467 def openSingleServiceEPG(self):
468 ref=self.session.nav.getCurrentlyPlayingServiceReference()
469 self.session.open(EPGSelection, ref)
471 def openSimilarList(self, eventid, refstr):
472 self.session.open(EPGSelection, refstr, None, eventid)
474 def getNowNext(self):
476 service = self.session.nav.getCurrentService()
477 info = service and service.info()
478 ptr = info and info.getEvent(0)
480 self.epglist.append(ptr)
481 ptr = info and info.getEvent(1)
483 self.epglist.append(ptr)
485 def __evEventInfoChanged(self):
486 if self.is_now_next and len(self.dlg_stack) == 1:
488 assert self.eventView
489 if len(self.epglist):
490 self.eventView.setEvent(self.epglist[0])
492 def openEventView(self):
493 ref = self.session.nav.getCurrentlyPlayingServiceReference()
495 if len(self.epglist) == 0:
496 self.is_now_next = False
497 epg = eEPGCache.getInstance()
498 ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
500 self.epglist.append(ptr)
501 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
503 self.epglist.append(ptr)
505 self.is_now_next = True
506 if len(self.epglist) > 0:
507 self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
508 self.dlg_stack.append(self.eventView)
510 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
511 self.openMultiServiceEPG(False)
513 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
514 if len(self.epglist) > 1:
515 tmp = self.epglist[0]
516 self.epglist[0]=self.epglist[1]
518 setEvent(self.epglist[0])
521 """provides a snr/agc/ber display"""
523 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
526 """provides a current/next event info display"""
528 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
529 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
531 class InfoBarServiceName:
533 self["CurrentService"] = CurrentService(self.session.nav)
536 """handles actions like seeking, pause"""
538 # ispause, isff, issm
539 SEEK_STATE_PLAY = (0, 0, 0, ">")
540 SEEK_STATE_PAUSE = (1, 0, 0, "||")
541 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
542 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
543 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
544 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
545 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
546 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
548 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
549 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
550 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
551 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
553 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
554 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
555 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
558 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
560 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
561 iPlayableService.evStart: self.__serviceStarted,
563 iPlayableService.evEOF: self.__evEOF,
564 iPlayableService.evSOF: self.__evSOF,
567 class InfoBarSeekActionMap(HelpableActionMap):
568 def __init__(self, screen, *args, **kwargs):
569 HelpableActionMap.__init__(self, screen, *args, **kwargs)
572 def action(self, contexts, action):
573 if action[:5] == "seek:":
574 time = int(action[5:])
575 self.screen.seekRelative(time * 90000)
578 return HelpableActionMap.action(self, contexts, action)
580 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
582 "pauseService": (self.pauseService, _("pause")),
583 "unPauseService": (self.unPauseService, _("continue")),
585 "seekFwd": (self.seekFwd, _("skip forward")),
586 "seekFwdDown": self.seekFwdDown,
587 "seekFwdUp": self.seekFwdUp,
588 "seekBack": (self.seekBack, _("skip backward")),
589 "seekBackDown": self.seekBackDown,
590 "seekBackUp": self.seekBackUp,
592 # give them a little more priority to win over color buttons
594 self.seekstate = self.SEEK_STATE_PLAY
595 self.onClose.append(self.delTimer)
597 self.fwdtimer = False
598 self.fwdKeyTimer = eTimer()
599 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
601 self.rwdtimer = False
602 self.rwdKeyTimer = eTimer()
603 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
605 self.onPlayStateChanged = [ ]
607 self.lockedBecauseOfSkipping = False
620 service = self.session.nav.getCurrentService()
624 seek = service.seek()
626 if seek is None or not seek.isCurrentlySeekable():
631 def isSeekable(self):
632 if self.getSeek() is None:
636 def __seekableStatusChanged(self):
637 print "seekable status changed!"
638 if not self.isSeekable():
639 self["SeekActions"].setEnabled(False)
640 print "not seekable, return to play"
641 self.setSeekState(self.SEEK_STATE_PLAY)
643 self["SeekActions"].setEnabled(True)
646 def __serviceStarted(self):
647 self.seekstate = self.SEEK_STATE_PLAY
649 def setSeekState(self, state):
650 service = self.session.nav.getCurrentService()
655 if not self.isSeekable():
656 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
657 state = self.SEEK_STATE_PLAY
659 pauseable = service.pause()
661 if pauseable is None:
662 print "not pauseable."
663 state = self.SEEK_STATE_PLAY
665 oldstate = self.seekstate
666 self.seekstate = state
669 if oldstate[i] != self.seekstate[i]:
670 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
672 for c in self.onPlayStateChanged:
675 self.checkSkipShowHideLock()
679 def pauseService(self):
680 if self.seekstate == self.SEEK_STATE_PAUSE:
681 print "pause, but in fact unpause"
682 self.unPauseService()
684 if self.seekstate == self.SEEK_STATE_PLAY:
685 print "yes, playing."
687 print "no", self.seekstate
689 self.setSeekState(self.SEEK_STATE_PAUSE);
691 def unPauseService(self):
693 if self.seekstate == self.SEEK_STATE_PLAY:
695 self.setSeekState(self.SEEK_STATE_PLAY)
697 def doSeek(self, seektime):
698 print "doseek", seektime
699 service = self.session.nav.getCurrentService()
703 seekable = self.getSeek()
707 seekable.seekTo(90 * seektime)
709 def seekFwdDown(self):
710 print "start fwd timer"
712 self.fwdKeyTimer.start(1000)
714 def seekBackDown(self):
715 print "start rewind timer"
717 self.rwdKeyTimer.start(1000)
722 self.fwdKeyTimer.stop()
723 self.fwdtimer = False
728 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
729 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
730 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
731 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
732 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
733 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
734 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
735 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
736 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
737 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
738 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
739 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
740 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
741 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
742 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
744 self.setSeekState(lookup[self.seekstate])
746 def seekBackUp(self):
749 self.rwdKeyTimer.stop()
750 self.rwdtimer = False
755 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
756 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
757 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
758 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
759 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
760 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
761 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
762 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
763 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
764 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
765 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
766 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
767 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
768 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
769 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
771 self.setSeekState(lookup[self.seekstate])
773 if self.seekstate == self.SEEK_STATE_PAUSE:
774 seekable = self.getSeek()
775 if seekable is not None:
776 seekable.seekRelative(-1, 3)
778 def fwdTimerFire(self):
779 print "Display seek fwd"
780 self.fwdKeyTimer.stop()
781 self.fwdtimer = False
782 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
784 def fwdSeekTo(self, minutes):
785 print "Seek", minutes, "minutes forward"
787 seekable = self.getSeek()
788 if seekable is not None:
789 seekable.seekRelative(1, minutes * 60 * 90000)
791 def rwdTimerFire(self):
793 self.rwdKeyTimer.stop()
794 self.rwdtimer = False
795 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
797 def rwdSeekTo(self, minutes):
799 self.fwdSeekTo(0 - minutes)
801 def checkSkipShowHideLock(self):
802 wantlock = self.seekstate != self.SEEK_STATE_PLAY
804 if self.lockedBecauseOfSkipping and not wantlock:
806 self.lockedBecauseOfSkipping = False
808 if wantlock and not self.lockedBecauseOfSkipping:
810 self.lockedBecauseOfSkipping = True
813 if self.seekstate != self.SEEK_STATE_PLAY:
814 self.setSeekState(self.SEEK_STATE_PAUSE)
816 #self.getSeek().seekRelative(1, -90000)
817 self.setSeekState(self.SEEK_STATE_PLAY)
819 self.setSeekState(self.SEEK_STATE_PAUSE)
822 self.setSeekState(self.SEEK_STATE_PLAY)
825 def seekRelative(self, diff):
826 seekable = self.getSeek()
827 if seekable is not None:
828 seekable.seekRelative(1, diff)
830 from Screens.PVRState import PVRState, TimeshiftState
832 class InfoBarPVRState:
833 def __init__(self, screen=PVRState):
834 self.onPlayStateChanged.append(self.__playStateChanged)
835 self.pvrStateDialog = self.session.instantiateDialog(screen)
836 self.onShow.append(self.__mayShow)
837 self.onHide.append(self.pvrStateDialog.hide)
840 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
841 self.pvrStateDialog.show()
843 def __playStateChanged(self, state):
844 playstateString = state[3]
845 self.pvrStateDialog["state"].setText(playstateString)
848 class InfoBarTimeshiftState(InfoBarPVRState):
850 InfoBarPVRState.__init__(self, screen=TimeshiftState)
852 class InfoBarShowMovies:
854 # i don't really like this class.
855 # it calls a not further specified "movie list" on up/down/movieList,
856 # so this is not more than an action map
858 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
860 "movieList": (self.showMovies, "movie list"),
861 "up": (self.showMovies, "movie list"),
862 "down": (self.showMovies, "movie list")
865 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
869 # Timeshift works the following way:
870 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
871 # - normal playback TUNER unused PLAY enable disable disable
872 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
873 # - user presess pause again FILE record PLAY enable disable enable
874 # - user fast forwards FILE record FF enable disable enable
875 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
876 # - user backwards FILE record BACK # !! enable disable enable
880 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
881 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
882 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
883 # - the user can now PVR around
884 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
885 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
887 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
888 # - if the user rewinds, or press pause, timeshift will be activated again
890 # note that a timeshift can be enabled ("recording") and
891 # activated (currently time-shifting).
893 class InfoBarTimeshift:
895 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
897 "timeshiftStart": (self.startTimeshift, _("start timeshift")), # the "yellow key"
898 "timeshiftStop": (self.stopTimeshift, _("stop timeshift")) # currently undefined :), probably 'TV'
900 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
902 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
903 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
904 }, prio=-1) # priority over record
906 self.timeshift_enabled = 0
907 self.timeshift_state = 0
908 self.ts_pause_timer = eTimer()
909 self.ts_pause_timer.timeout.get().append(self.pauseService)
911 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
913 iPlayableService.evStart: self.__serviceStarted,
914 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
917 def getTimeshift(self):
918 service = self.session.nav.getCurrentService()
919 return service and service.timeshift()
921 def startTimeshift(self):
922 print "enable timeshift"
923 ts = self.getTimeshift()
925 # self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
926 # print "no ts interface"
929 if self.timeshift_enabled:
930 print "hu, timeshift already enabled?"
932 if not ts.startTimeshift():
934 self.timeshift_enabled = 1
936 # we remove the "relative time" for now.
937 #self.pvrStateDialog["timeshift"].setRelative(time.time())
940 self.setSeekState(self.SEEK_STATE_PAUSE)
942 # enable the "TimeshiftEnableActions", which will override
943 # the startTimeshift actions
944 self.__seekableStatusChanged()
946 print "timeshift failed"
948 def stopTimeshift(self):
949 if not self.timeshift_enabled:
951 print "disable timeshift"
952 ts = self.getTimeshift()
955 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
957 def stopTimeshiftConfirmed(self, confirmed):
961 ts = self.getTimeshift()
966 self.timeshift_enabled = 0
969 self.__seekableStatusChanged()
971 # activates timeshift, and seeks to (almost) the end
972 def activateTimeshiftEnd(self):
973 ts = self.getTimeshift()
978 if ts.isTimeshiftActive():
979 print "!! activate timeshift called - but shouldn't this be a normal pause?"
982 self.setSeekState(self.SEEK_STATE_PLAY)
983 ts.activateTimeshift()
986 # same as activateTimeshiftEnd, but pauses afterwards.
987 def activateTimeshiftEndAndPause(self):
988 state = self.seekstate
989 self.activateTimeshiftEnd()
991 # well, this is "andPause", but it could be pressed from pause,
992 # when pausing on the (fake-)"live" picture, so an un-pause
995 print "now, pauseService"
996 if state == self.SEEK_STATE_PLAY:
997 print "is PLAYING, start pause timer"
998 self.ts_pause_timer.start(200, 1)
1001 self.unPauseService()
1003 def __seekableStatusChanged(self):
1006 print "self.isSeekable", self.isSeekable()
1007 print "self.timeshift_enabled", self.timeshift_enabled
1009 # when this service is not seekable, but timeshift
1010 # is enabled, this means we can activate
1012 if not self.isSeekable() and self.timeshift_enabled:
1015 print "timeshift activate:", enabled
1016 self["TimeshiftActivateActions"].setEnabled(enabled)
1018 def __serviceStarted(self):
1019 self.timeshift_enabled = False
1020 self.__seekableStatusChanged()
1022 from Screens.PiPSetup import PiPSetup
1024 class InfoBarExtensions:
1025 def __init__(self, useServicePath = True):
1026 self.session.pipshown = False
1027 self.useServicePath = useServicePath
1029 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1031 "extensions": (self.extensions, _("view extensions...")),
1040 def extensions(self):
1042 if self.session.pipshown == False:
1043 list.append((_("Activate Picture in Picture"), self.PIPON))
1044 elif self.session.pipshown == True:
1045 list.append((_("Disable Picture in Picture"), self.PIPOFF))
1046 list.append((_("Move Picture in Picture"), self.MOVEPIP))
1047 list.append((_("Swap services"), self.PIPSWAP))
1049 s = self.getCurrentServiceSubtitle()
1050 l = s and s.getSubtitleList() or [ ]
1053 list.append(("Enable Subtitles: " + x[0], self.ENABLE_SUBTITLE, x[1]))
1055 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
1057 def extensionCallback(self, answer):
1058 if answer is not None:
1059 if answer[1] == self.PIPON:
1060 self.session.pip = self.session.instantiateDialog(PictureInPicture)
1061 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1062 if self.session.pip.playService(newservice):
1063 self.session.pipshown = True
1064 if self.useServicePath:
1065 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1067 self.session.pipshown = False
1068 del self.session.pip
1069 self.session.nav.playService(newservice)
1070 elif answer[1] == self.PIPOFF:
1071 del self.session.pip
1072 self.session.pipshown = False
1073 elif answer[1] == self.PIPSWAP:
1074 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1075 if self.useServicePath:
1076 if self.session.pip.servicePath:
1077 servicepath = self.servicelist.getCurrentServicePath()
1078 ref=servicepath[len(servicepath)-1]
1079 pipref=self.session.pip.getCurrentService()
1080 self.session.pip.playService(swapservice)
1081 self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1082 if pipref.toString() != ref.toString(): # is a subservice ?
1083 self.session.nav.stopService() # stop portal
1084 self.session.nav.playService(pipref) # start subservice
1085 self.session.pip.servicePath=servicepath
1086 elif answer[1] == self.MOVEPIP:
1087 self.session.open(PiPSetup, pip = self.session.pip)
1088 elif answer[1] == self.ENABLE_SUBTITLE:
1089 self.selected_subtitle = answer[2]
1090 self.subtitles_enabled = True
1092 from RecordTimer import parseEvent
1094 class InfoBarInstantRecord:
1095 """Instant Record - handles the instantRecord action in order to
1096 start/stop instant records"""
1098 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1100 "instantRecord": (self.instantRecord, _("Instant Record...")),
1103 self["BlinkingPoint"] = BlinkingPixmapConditional()
1104 self["BlinkingPoint"].hide()
1105 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1107 def stopCurrentRecording(self, entry = -1):
1108 if entry is not None and entry != -1:
1109 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1110 self.recording.remove(self.recording[entry])
1112 def startInstantRecording(self, limitEvent = False):
1113 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1115 # try to get event info
1118 service = self.session.nav.getCurrentService()
1119 epg = eEPGCache.getInstance()
1120 event = epg.lookupEventTime(serviceref, -1, 0)
1122 info = service.info()
1123 ev = info.getEvent(0)
1129 end = time.time() + 3600 * 10
1130 name = "instant record"
1134 if event is not None:
1135 curEvent = parseEvent(event)
1137 description = curEvent[3]
1138 eventid = curEvent[4]
1143 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1145 data = (begin, end, name, description, eventid)
1147 recording = self.session.nav.recordWithTimer(serviceref, *data)
1148 recording.dontSave = True
1149 self.recording.append(recording)
1151 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1153 def isInstantRecordRunning(self):
1154 print "self.recording:", self.recording
1155 if len(self.recording) > 0:
1156 for x in self.recording:
1161 def recordQuestionCallback(self, answer):
1162 print "pre:\n", self.recording
1164 if answer is None or answer[1] == "no":
1167 recording = self.recording[:]
1169 if not x in self.session.nav.RecordTimer.timer_list:
1170 self.recording.remove(x)
1171 elif x.dontSave and x.isRunning():
1172 list.append(TimerEntryComponent(x, False))
1174 if answer[1] == "changeduration":
1175 if len(self.recording) == 1:
1176 self.changeDuration(0)
1178 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1179 elif answer[1] == "stop":
1180 if len(self.recording) == 1:
1181 self.stopCurrentRecording(0)
1183 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1184 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1186 if answer[1] == "event":
1188 if answer[1] == "manualduration":
1189 self.selectedEntry = len(self.recording)
1190 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1191 self.startInstantRecording(limitEvent = limitEvent)
1193 print "after:\n", self.recording
1195 def changeDuration(self, entry):
1196 if entry is not None:
1197 self.selectedEntry = entry
1198 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1200 def inputCallback(self, value):
1201 if value is not None:
1202 print "stopping recording after", int(value), "minutes."
1203 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1204 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1206 def instantRecord(self):
1208 stat = os.stat(resolveFilename(SCOPE_HDD))
1210 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1213 if self.isInstantRecordRunning():
1214 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")])
1216 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")])
1218 from Tools.ISO639 import LanguageCodes
1220 class InfoBarAudioSelection:
1222 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1224 "audioSelection": (self.audioSelection, _("Audio Options...")),
1227 def audioSelection(self):
1228 service = self.session.nav.getCurrentService()
1229 audio = service and service.audioTracks()
1230 self.audioTracks = audio
1231 n = audio and audio.getNumberOfTracks()
1232 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1234 print "tlist:", tlist
1236 self.audioChannel = service.audioChannel()
1239 i = audio.getTrackInfo(x)
1240 language = i.getLanguage()
1241 description = i.getDescription()
1243 if len(language) == 3:
1244 if language in LanguageCodes:
1245 language = LanguageCodes[language][0]
1247 if len(description):
1248 description += " (" + language + ")"
1250 description = language
1252 tlist.append((description, x))
1254 selectedAudio = tlist[0][1]
1255 tlist.sort(lambda x,y : cmp(x[0], y[0]))
1259 if x[1] != selectedAudio:
1264 tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1265 self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1267 del self.audioTracks
1269 def audioSelected(self, audio):
1270 if audio is not None:
1271 if isinstance(audio[1], str):
1272 if audio[1] == "mode":
1273 keys = ["red", "green", "yellow"]
1274 selection = self.audioChannel.getCurrentChannel()
1275 tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1276 self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1278 del self.audioChannel
1279 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1280 self.audioTracks.selectTrack(audio[1])
1282 del self.audioChannel
1283 del self.audioTracks
1285 def modeSelected(self, mode):
1286 if mode is not None:
1287 self.audioChannel.selectChannel(mode[1])
1288 del self.audioChannel
1291 class InfoBarSubserviceSelection:
1293 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1295 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1298 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1300 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1301 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1303 self["SubserviceQuickzapAction"].setEnabled(False)
1305 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1307 def checkSubservicesAvail(self, ev):
1308 if ev == iPlayableService.evUpdatedEventInfo:
1309 service = self.session.nav.getCurrentService()
1310 subservices = service and service.subServices()
1311 if not subservices or subservices.getNumberOfSubservices() == 0:
1312 self["SubserviceQuickzapAction"].setEnabled(False)
1314 def nextSubservice(self):
1315 self.changeSubservice(+1)
1317 def prevSubservice(self):
1318 self.changeSubservice(-1)
1320 def changeSubservice(self, direction):
1321 service = self.session.nav.getCurrentService()
1322 subservices = service and service.subServices()
1323 n = subservices and subservices.getNumberOfSubservices()
1326 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1328 if subservices.getSubservice(x).toString() == ref.toString():
1331 selection += direction
1336 newservice = subservices.getSubservice(selection)
1337 if newservice.valid():
1340 self.session.nav.playService(newservice)
1342 def subserviceSelection(self):
1343 service = self.session.nav.getCurrentService()
1344 subservices = service and service.subServices()
1346 n = subservices and subservices.getNumberOfSubservices()
1349 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1352 i = subservices.getSubservice(x)
1353 if i.toString() == ref.toString():
1355 tlist.append((i.getName(), i))
1357 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1359 keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1361 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection + 2, keys = keys)
1363 def subserviceSelected(self, service):
1364 if not service is None:
1365 if isinstance(service[1], str):
1366 if service[1] == "quickzap":
1367 from Screens.SubservicesQuickzap import SubservicesQuickzap
1368 self.session.open(SubservicesQuickzap, service[2])
1370 self["SubserviceQuickzapAction"].setEnabled(True)
1371 self.session.nav.playService(service[1])
1373 class InfoBarAdditionalInfo:
1375 self["NimA"] = Pixmap()
1376 self["NimB"] = Pixmap()
1377 self["NimA_Active"] = Pixmap()
1378 self["NimB_Active"] = Pixmap()
1380 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1381 self["TimeshiftPossible"] = self["RecordingPossible"]
1382 self["ExtensionsAvailable"] = Boolean(fixed=1)
1384 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1385 res_mgr = eDVBResourceManagerPtr()
1386 if eDVBResourceManager.getInstance(res_mgr) == 0:
1387 res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1389 def tunerUseMaskChanged(self, mask):
1391 self["NimA_Active"].show()
1393 self["NimA_Active"].hide()
1395 self["NimB_Active"].show()
1397 self["NimB_Active"].hide()
1399 def checkTunerState(self, service):
1400 info = service.frontendInfo()
1401 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1402 if feNumber is None:
1412 def gotServiceEvent(self, ev):
1413 service = self.session.nav.getCurrentService()
1414 if ev == iPlayableService.evStart:
1415 self.checkTunerState(service)
1417 class InfoBarNotifications:
1419 self.onExecBegin.append(self.checkNotifications)
1420 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1421 self.onClose.append(self.__removeNotification)
1423 def __removeNotification(self):
1424 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1426 def checkNotificationsIfExecing(self):
1428 self.checkNotifications()
1430 def checkNotifications(self):
1431 if len(Notifications.notifications):
1432 n = Notifications.notifications[0]
1433 Notifications.notifications = Notifications.notifications[1:]
1436 self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1438 self.session.open(n[1], *n[2], **n[3])
1440 class InfoBarServiceNotifications:
1442 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1444 iPlayableService.evEnd: self.serviceHasEnded
1447 def serviceHasEnded(self):
1448 print "service end!"
1451 self.setSeekState(self.SEEK_STATE_PLAY)
1455 class InfoBarCueSheetSupport:
1461 ENABLE_RESUME_SUPPORT = False
1464 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1466 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1467 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1468 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1472 self.is_closing = False
1473 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1475 iPlayableService.evStart: self.__serviceStarted,
1478 def __serviceStarted(self):
1481 print "new service started! trying to download cuts!"
1482 self.downloadCuesheet()
1484 if self.ENABLE_RESUME_SUPPORT:
1487 for (pts, what) in self.cut_list:
1488 if what == self.CUT_TYPE_LAST:
1491 if last is not None:
1492 self.resume_point = last
1493 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1495 def playLastCB(self, answer):
1497 seekable = self.__getSeekable()
1498 if seekable is not None:
1499 seekable.seekTo(self.resume_point)
1501 def __getSeekable(self):
1502 service = self.session.nav.getCurrentService()
1505 return service.seek()
1507 def cueGetCurrentPosition(self):
1508 seek = self.__getSeekable()
1511 r = seek.getPlayPosition()
1516 def jumpPreviousNextMark(self, cmp, alternative=None):
1517 current_pos = self.cueGetCurrentPosition()
1518 if current_pos is None:
1520 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1521 if mark is not None:
1523 elif alternative is not None:
1528 seekable = self.__getSeekable()
1529 if seekable is not None:
1530 seekable.seekTo(pts)
1532 def jumpPreviousMark(self):
1533 # we add 2 seconds, so if the play position is <2s after
1534 # the mark, the mark before will be used
1535 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1537 def jumpNextMark(self):
1538 self.jumpPreviousNextMark(lambda x: x)
1540 def getNearestCutPoint(self, pts, cmp=abs):
1543 for cp in self.cut_list:
1544 diff = cmp(cp[0] - pts)
1545 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1549 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1550 current_pos = self.cueGetCurrentPosition()
1551 if current_pos is None:
1552 print "not seekable"
1555 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1557 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1559 return nearest_cutpoint
1561 self.removeMark(nearest_cutpoint)
1562 elif not onlyremove and not onlyreturn:
1563 self.addMark((current_pos, self.CUT_TYPE_MARK))
1568 def addMark(self, point):
1569 bisect.insort(self.cut_list, point)
1570 self.uploadCuesheet()
1572 def removeMark(self, point):
1573 self.cut_list.remove(point)
1574 self.uploadCuesheet()
1576 def __getCuesheet(self):
1577 service = self.session.nav.getCurrentService()
1580 return service.cueSheet()
1582 def uploadCuesheet(self):
1583 cue = self.__getCuesheet()
1586 print "upload failed, no cuesheet interface"
1588 cue.setCutList(self.cut_list)
1590 def downloadCuesheet(self):
1591 cue = self.__getCuesheet()
1594 print "upload failed, no cuesheet interface"
1596 self.cut_list = cue.getCutList()
1598 class InfoBarSummary(Screen):
1600 <screen position="0,0" size="132,64">
1601 <widget source="CurrentTime" render="Label" position="50,46" size="82,18" font="Regular;16" >
1602 <convert type="ClockToText">WithSeconds</convert>
1604 <widget source="CurrentService" render="Label" position="0,4" size="132,42" font="Regular;18" >
1605 <convert type="ServiceName">Name</convert>
1609 def __init__(self, session, parent):
1610 Screen.__init__(self, session)
1611 self["CurrentService"] = CurrentService(self.session.nav)
1612 self["CurrentTime"] = Clock()
1614 class InfoBarSummarySupport:
1618 def createSummary(self):
1619 return InfoBarSummary
1621 class InfoBarTeletextPlugin:
1623 self.teletext_plugin = None
1625 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1626 self.teletext_plugin = p
1628 if self.teletext_plugin is not None:
1629 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1631 "startTeletext": (self.startTeletext, _("View teletext..."))
1634 print "no teletext plugin found!"
1636 def startTeletext(self):
1637 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1639 class InfoBarSubtitleSupport(object):
1641 object.__init__(self)
1642 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1643 self.__subtitles_enabled = False
1645 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1647 iPlayableService.evStart: self.__serviceStarted,
1650 def __serviceStarted(self):
1651 # reenable if it was enabled
1652 r = self.__subtitles_enabled
1653 self.__subtitles_enabled = False
1654 self.__selected_subtitle = None
1655 self.setSubtitlesEnable(r)
1657 def getCurrentServiceSubtitle(self):
1658 service = self.session.nav.getCurrentService()
1659 return service and service.subtitle()
1661 def setSubtitlesEnable(self, enable=True):
1662 subtitle = self.getCurrentServiceSubtitle()
1663 if enable and self.__selected_subtitle:
1664 if subtitle and not self.__subtitles_enabled:
1665 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1666 self.subtitle_window.show()
1667 self.__subtitles_enabled = True
1670 subtitle.disableSubtitles(self.subtitle_window.instance)
1672 self.subtitle_window.hide()
1673 self.__subtitles_enabled = False
1675 def setSelectedSubtitle(self, subtitle):
1676 if self.__selected_subtitle != subtitle and self.subtitles_enabled:
1678 self.__selected_subtitle = subtitle
1679 self.__serviceStarted()
1681 self.__selected_subtitle = subtitle
1683 subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1684 selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)