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
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 ServiceReference import ServiceReference
34 from Tools import Notifications
35 from Tools.Directories import *
37 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
44 from Components.config import config, currentConfigSelectionElement
47 from Menu import MainMenu, mdom
51 self.dishDialog = self.session.instantiateDialog(Dish)
52 self.onLayoutFinish.append(self.dishDialog.show)
54 class InfoBarShowHide:
55 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
63 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
65 "toggleShow": self.toggleShow,
69 self.__state = self.STATE_SHOWN
72 self.onExecBegin.append(self.show)
74 self.hideTimer = eTimer()
75 self.hideTimer.timeout.get().append(self.doTimerHide)
76 self.hideTimer.start(5000, True)
78 self.onShow.append(self.__onShow)
79 self.onHide.append(self.__onHide)
82 self.__state = self.STATE_SHOWN
85 def startHideTimer(self):
86 if self.__state == self.STATE_SHOWN and not self.__locked:
87 self.hideTimer.start(5000, True)
90 self.__state = self.STATE_HIDDEN
96 def doTimerHide(self):
98 if self.__state == self.STATE_SHOWN:
101 def toggleShow(self):
102 if self.__state == self.STATE_SHOWN:
104 self.hideTimer.stop()
105 elif self.__state == self.STATE_HIDDEN:
109 self.__locked = self.__locked + 1
112 self.hideTimer.stop()
114 def unlockShow(self):
115 self.__locked = self.__locked - 1
117 self.startHideTimer()
119 # def startShow(self):
120 # self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
121 # self.__state = self.STATE_SHOWN
123 # def startHide(self):
124 # self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
125 # self.__state = self.STATE_HIDDEN
127 class NumberZap(Screen):
134 self.close(int(self["number"].getText()))
136 def keyNumberGlobal(self, number):
137 self.Timer.start(3000, True) #reset timer
138 self.field = self.field + str(number)
139 self["number"].setText(self.field)
140 if len(self.field) >= 4:
143 def __init__(self, session, number):
144 Screen.__init__(self, session)
145 self.field = str(number)
147 self["channel"] = Label(_("Channel:"))
149 self["number"] = Label(self.field)
151 self["actions"] = NumberActionMap( [ "SetupActions" ],
155 "1": self.keyNumberGlobal,
156 "2": self.keyNumberGlobal,
157 "3": self.keyNumberGlobal,
158 "4": self.keyNumberGlobal,
159 "5": self.keyNumberGlobal,
160 "6": self.keyNumberGlobal,
161 "7": self.keyNumberGlobal,
162 "8": self.keyNumberGlobal,
163 "9": self.keyNumberGlobal,
164 "0": self.keyNumberGlobal
167 self.Timer = eTimer()
168 self.Timer.timeout.get().append(self.keyOK)
169 self.Timer.start(3000, True)
171 class InfoBarNumberZap:
172 """ Handles an initial number for NumberZapping """
174 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
176 "1": self.keyNumberGlobal,
177 "2": self.keyNumberGlobal,
178 "3": self.keyNumberGlobal,
179 "4": self.keyNumberGlobal,
180 "5": self.keyNumberGlobal,
181 "6": self.keyNumberGlobal,
182 "7": self.keyNumberGlobal,
183 "8": self.keyNumberGlobal,
184 "9": self.keyNumberGlobal,
185 "0": self.keyNumberGlobal,
188 def keyNumberGlobal(self, number):
189 # print "You pressed number " + str(number)
191 self.servicelist.recallPrevService()
194 self.session.openWithCallback(self.numberEntered, NumberZap, number)
196 def numberEntered(self, retval):
197 # print self.servicelist
199 self.zapToNumber(retval)
201 def searchNumberHelper(self, serviceHandler, num, bouquet):
202 servicelist = serviceHandler.list(bouquet)
203 if not servicelist is None:
205 serviceIterator = servicelist.getNext()
206 if not serviceIterator.valid(): #check end of list
208 if serviceIterator.flags: #assume normal dvb service have no flags set
211 if not num: #found service with searched number ?
212 return serviceIterator, 0
215 def zapToNumber(self, number):
216 bouquet = self.servicelist.bouquet_root
218 serviceHandler = eServiceCenter.getInstance()
219 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
220 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
222 bouquetlist = serviceHandler.list(bouquet)
223 if not bouquetlist is None:
225 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
226 if not bouquet.valid(): #check end of list
228 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
230 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
231 if not service is None:
232 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
233 self.servicelist.clearPath()
234 if self.servicelist.bouquet_root != bouquet:
235 self.servicelist.enterPath(self.servicelist.bouquet_root)
236 self.servicelist.enterPath(bouquet)
237 self.servicelist.setCurrentSelection(service) #select the service in servicelist
238 self.servicelist.zap()
240 config.misc.initialchannelselection = configElementBoolean("config.misc.initialchannelselection", 1);
242 class InfoBarChannelSelection:
243 """ ChannelSelection - handles the channelSelection dialog and the initial
244 channelChange actions which open the channelSelection dialog """
247 self.servicelist = self.session.instantiateDialog(ChannelSelection)
249 if config.misc.initialchannelselection.value == 1:
250 self.onShown.append(self.firstRun)
252 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
254 "switchChannelUp": self.switchChannelUp,
255 "switchChannelDown": self.switchChannelDown,
256 "zapUp": (self.zapUp, _("previous channel")),
257 "zapDown": (self.zapDown, _("next channel")),
258 "historyBack": (self.historyBack, _("previous channel in history")),
259 "historyNext": (self.historyNext, _("next channel in history"))
263 self.onShown.remove(self.firstRun)
264 config.misc.initialchannelselection.value = 0
265 config.misc.initialchannelselection.save()
266 self.switchChannelDown()
268 def historyBack(self):
269 self.servicelist.historyBack()
271 def historyNext(self):
272 self.servicelist.historyNext()
274 def switchChannelUp(self):
275 self.servicelist.moveUp()
276 self.session.execDialog(self.servicelist)
278 def switchChannelDown(self):
279 self.servicelist.moveDown()
280 self.session.execDialog(self.servicelist)
283 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
284 if self.servicelist.inBouquet() and self.servicelist.atBegin():
285 self.servicelist.prevBouquet()
286 self.servicelist.moveUp()
287 self.servicelist.zap()
291 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
292 self.servicelist.nextBouquet()
294 self.servicelist.moveDown()
295 self.servicelist.zap()
299 """ Handles a menu action, to open the (main) menu """
301 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
303 "mainMenu": (self.mainMenu, "Enter main menu..."),
307 print "loading mainmenu XML..."
308 menu = mdom.childNodes[0]
309 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
310 self.session.open(MainMenu, menu, menu.childNodes)
312 class InfoBarSimpleEventView:
313 """ Opens the Eventview for now/next """
315 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
317 "showEventInfo": (self.openEventView, _("show event details")),
320 def openEventView(self):
322 service = self.session.nav.getCurrentService()
323 ref = self.session.nav.getCurrentlyPlayingServiceReference()
324 info = service.info()
327 self.epglist.append(ptr)
330 self.epglist.append(ptr)
331 if len(self.epglist) > 0:
332 self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
334 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
335 if len(self.epglist) > 1:
336 tmp = self.epglist[0]
337 self.epglist[0]=self.epglist[1]
339 setEvent(self.epglist[0])
342 """ EPG - Opens an EPG list when the showEPGList action fires """
344 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
346 "showEventInfo": (self.openEventView, _("show EPG...")),
349 def zapToService(self, service):
350 if not service is None:
351 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
352 self.servicelist.clearPath()
353 if self.servicelist.bouquet_root != self.epg_bouquet:
354 self.servicelist.enterPath(self.servicelist.bouquet_root)
355 self.servicelist.enterPath(self.epg_bouquet)
356 self.servicelist.setCurrentSelection(service) #select the service in servicelist
357 self.servicelist.zap()
359 def openBouquetEPG(self, bouquet, withCallback=True):
360 ptr=eEPGCache.getInstance()
362 servicelist = eServiceCenter.getInstance().list(bouquet)
363 if not servicelist is None:
365 service = servicelist.getNext()
366 if not service.valid(): #check if end of list
368 if service.flags: #ignore non playable services
370 services.append(ServiceReference(service))
372 self.epg_bouquet = bouquet
374 self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
376 self.session.open(EPGSelection, services, self.zapToService)
378 def closed(self, ret):
382 def openMultiServiceEPG(self, withCallback=True):
383 bouquets = self.servicelist.getBouquetList()
388 if cnt > 1: # show bouquet list
390 self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
392 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
394 self.openBouquetEPG(bouquets[0][1], withCallback)
396 def openSingleServiceEPG(self):
397 ref=self.session.nav.getCurrentlyPlayingServiceReference()
398 ptr=eEPGCache.getInstance()
399 self.session.openWithCallback(self.closed, EPGSelection, ref)
401 def openEventView(self):
403 service = self.session.nav.getCurrentService()
404 ref = self.session.nav.getCurrentlyPlayingServiceReference()
405 info = service.info()
408 self.epglist.append(ptr)
411 self.epglist.append(ptr)
412 if len(self.epglist) == 0:
413 epg = eEPGCache.getInstance()
414 ptr = epg.lookupEventTime(ref, -1)
416 self.epglist.append(ptr)
417 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
419 self.epglist.append(ptr)
420 if len(self.epglist) > 0:
421 self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
423 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
424 self.openMultiServiceEPG(False)
426 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
427 if len(self.epglist) > 1:
428 tmp = self.epglist[0]
429 self.epglist[0]=self.epglist[1]
431 setEvent(self.epglist[0])
434 """provides a snr/agc/ber display"""
436 self["snr"] = Label()
437 self["agc"] = Label()
438 self["ber"] = Label()
439 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, self.session.nav.getCurrentService)
440 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, self.session.nav.getCurrentService)
441 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, self.session.nav.getCurrentService)
442 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, self.session.nav.getCurrentService)
443 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, self.session.nav.getCurrentService)
444 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, self.session.nav.getCurrentService)
445 self.timer = eTimer()
446 self.timer.timeout.get().append(self.updateTunerInfo)
447 self.timer.start(1000)
449 def updateTunerInfo(self):
450 if self.instance.isVisible():
451 self["snr_percent"].update()
452 self["agc_percent"].update()
453 self["ber_count"].update()
454 self["snr_progress"].update()
455 self["agc_progress"].update()
456 self["ber_progress"].update()
459 """provides a current/next event info display"""
461 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
462 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
464 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
465 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
467 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
468 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
470 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
472 class InfoBarServiceName:
474 self["ServiceName"] = ServiceName(self.session.nav)
477 """handles actions like seeking, pause"""
479 # ispause, isff, issm
480 SEEK_STATE_PLAY = (0, 0, 0, ">")
481 SEEK_STATE_PAUSE = (1, 0, 0, "||")
482 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
483 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
484 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
485 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
486 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
487 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
489 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
490 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
491 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
492 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
494 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
495 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
496 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
499 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
501 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
502 iPlayableService.evStart: self.__serviceStarted,
504 iPlayableService.evEOF: self.__evEOF,
505 iPlayableService.evSOF: self.__evSOF,
508 class InfoBarSeekActionMap(HelpableActionMap):
509 def __init__(self, screen, *args, **kwargs):
510 HelpableActionMap.__init__(self, screen, *args, **kwargs)
513 def action(self, contexts, action):
514 if action[:5] == "seek:":
515 time = int(action[5:])
516 self.screen.seekRelative(time * 90000)
519 return HelpableActionMap.action(self, contexts, action)
521 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
523 "pauseService": (self.pauseService, "pause"),
524 "unPauseService": (self.unPauseService, "continue"),
526 "seekFwd": (self.seekFwd, "skip forward"),
527 "seekFwdDown": self.seekFwdDown,
528 "seekFwdUp": self.seekFwdUp,
529 "seekBack": (self.seekBack, "skip backward"),
530 "seekBackDown": self.seekBackDown,
531 "seekBackUp": self.seekBackUp,
533 # give them a little more priority to win over color buttons
535 self.seekstate = self.SEEK_STATE_PLAY
536 self.onClose.append(self.delTimer)
538 self.fwdtimer = False
539 self.fwdKeyTimer = eTimer()
540 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
542 self.rwdtimer = False
543 self.rwdKeyTimer = eTimer()
544 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
546 self.onPlayStateChanged = [ ]
548 self.lockedBecauseOfSkipping = False
561 service = self.session.nav.getCurrentService()
565 seek = service.seek()
567 if seek is None or not seek.isCurrentlySeekable():
572 def isSeekable(self):
573 if self.getSeek() is None:
577 def __seekableStatusChanged(self):
578 print "seekable status changed!"
579 if not self.isSeekable():
580 self["SeekActions"].setEnabled(False)
581 print "not seekable, return to play"
582 self.setSeekState(self.SEEK_STATE_PLAY)
584 self["SeekActions"].setEnabled(True)
587 def __serviceStarted(self):
588 self.seekstate = self.SEEK_STATE_PLAY
590 def setSeekState(self, state):
591 service = self.session.nav.getCurrentService()
596 if not self.isSeekable():
597 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
598 state = self.SEEK_STATE_PLAY
600 pauseable = service.pause()
602 if pauseable is None:
603 print "not pauseable."
604 state = self.SEEK_STATE_PLAY
606 oldstate = self.seekstate
607 self.seekstate = state
610 if oldstate[i] != self.seekstate[i]:
611 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
613 for c in self.onPlayStateChanged:
616 self.checkSkipShowHideLock()
620 def pauseService(self):
621 if self.seekstate == self.SEEK_STATE_PAUSE:
622 print "pause, but in fact unpause"
623 self.unPauseService()
625 if self.seekstate == self.SEEK_STATE_PLAY:
626 print "yes, playing."
628 print "no", self.seekstate
630 self.setSeekState(self.SEEK_STATE_PAUSE);
632 def unPauseService(self):
634 self.setSeekState(self.SEEK_STATE_PLAY);
636 def doSeek(self, seektime):
637 print "doseek", seektime
638 service = self.session.nav.getCurrentService()
642 seekable = self.getSeek()
646 seekable.seekTo(90 * seektime)
648 def seekFwdDown(self):
649 print "start fwd timer"
651 self.fwdKeyTimer.start(1000)
653 def seekBackDown(self):
654 print "start rewind timer"
656 self.rwdKeyTimer.start(1000)
661 self.fwdKeyTimer.stop()
662 self.fwdtimer = False
667 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
668 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
669 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
670 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
671 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
672 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
673 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
674 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
675 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
676 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
677 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
678 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
679 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
680 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
681 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
683 self.setSeekState(lookup[self.seekstate])
685 def seekBackUp(self):
688 self.rwdKeyTimer.stop()
689 self.rwdtimer = False
694 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
695 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
696 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
697 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
698 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
699 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
700 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
701 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
702 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
703 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
704 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
705 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
706 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
707 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
708 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
710 self.setSeekState(lookup[self.seekstate])
712 if self.seekstate == self.SEEK_STATE_PAUSE:
713 seekable = self.getSeek()
714 if seekable is not None:
715 seekable.seekRelative(-1, 3)
717 def fwdTimerFire(self):
718 print "Display seek fwd"
719 self.fwdKeyTimer.stop()
720 self.fwdtimer = False
721 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
723 def fwdSeekTo(self, minutes):
724 print "Seek", minutes, "minutes forward"
726 seekable = self.getSeek()
727 if seekable is not None:
728 seekable.seekRelative(1, minutes * 60 * 90000)
730 def rwdTimerFire(self):
732 self.rwdKeyTimer.stop()
733 self.rwdtimer = False
734 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
736 def rwdSeekTo(self, minutes):
738 self.fwdSeekTo(0 - minutes)
740 def checkSkipShowHideLock(self):
741 wantlock = self.seekstate != self.SEEK_STATE_PLAY
743 if self.lockedBecauseOfSkipping and not wantlock:
745 self.lockedBecauseOfSkipping = False
747 if wantlock and not self.lockedBecauseOfSkipping:
749 self.lockedBecauseOfSkipping = True
752 if self.seekstate != self.SEEK_STATE_PLAY:
753 self.setSeekState(self.SEEK_STATE_PAUSE)
755 #self.getSeek().seekRelative(1, -90000)
756 self.setSeekState(self.SEEK_STATE_PLAY)
758 self.setSeekState(self.SEEK_STATE_PAUSE)
761 self.setSeekState(self.SEEK_STATE_PLAY)
764 def seekRelative(self, diff):
765 seekable = self.getSeek()
766 if seekable is not None:
767 seekable.seekRelative(1, diff)
769 from Screens.PVRState import PVRState, TimeshiftState
771 class InfoBarPVRState:
772 def __init__(self, screen=PVRState):
773 self.onPlayStateChanged.append(self.__playStateChanged)
774 self.pvrStateDialog = self.session.instantiateDialog(screen)
775 self.onShow.append(self.__mayShow)
776 self.onHide.append(self.pvrStateDialog.hide)
779 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
780 self.pvrStateDialog.show()
782 def __playStateChanged(self, state):
783 playstateString = state[3]
784 self.pvrStateDialog["state"].setText(playstateString)
787 class InfoBarTimeshiftState(InfoBarPVRState):
789 InfoBarPVRState.__init__(self, screen=TimeshiftState)
792 class InfoBarShowMovies:
794 # i don't really like this class.
795 # it calls a not further specified "movie list" on up/down/movieList,
796 # so this is not more than an action map
798 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
800 "movieList": (self.showMovies, "movie list"),
801 "up": (self.showMovies, "movie list"),
802 "down": (self.showMovies, "movie list")
805 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
809 # Timeshift works the following way:
810 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
811 # - normal playback TUNER unused PLAY enable disable disable
812 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
813 # - user presess pause again FILE record PLAY enable disable enable
814 # - user fast forwards FILE record FF enable disable enable
815 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
816 # - user backwards FILE record BACK # !! enable disable enable
820 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
821 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
822 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
823 # - the user can now PVR around
824 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
825 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
827 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
828 # - if the user rewinds, or press pause, timeshift will be activated again
830 # note that a timeshift can be enabled ("recording") and
831 # activated (currently time-shifting).
833 class InfoBarTimeshift:
835 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
837 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
838 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
840 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
842 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
843 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
844 }, prio=-1) # priority over record
846 self.timeshift_enabled = 0
847 self.timeshift_state = 0
848 self.ts_pause_timer = eTimer()
849 self.ts_pause_timer.timeout.get().append(self.pauseService)
851 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
853 iPlayableService.evStart: self.__serviceStarted,
854 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
857 def getTimeshift(self):
858 service = self.session.nav.getCurrentService()
859 return service.timeshift()
861 def startTimeshift(self):
862 print "enable timeshift"
863 ts = self.getTimeshift()
865 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
866 print "no ts interface"
869 if self.timeshift_enabled:
870 print "hu, timeshift already enabled?"
872 if not ts.startTimeshift():
874 self.timeshift_enabled = 1
875 self.pvrStateDialog["timeshift"].setRelative(time.time())
878 self.setSeekState(self.SEEK_STATE_PAUSE)
880 # enable the "TimeshiftEnableActions", which will override
881 # the startTimeshift actions
882 self.__seekableStatusChanged()
884 print "timeshift failed"
886 def stopTimeshift(self):
887 if not self.timeshift_enabled:
889 print "disable timeshift"
890 ts = self.getTimeshift()
893 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
895 def stopTimeshiftConfirmed(self, confirmed):
899 ts = self.getTimeshift()
904 self.timeshift_enabled = 0
907 self.__seekableStatusChanged()
909 # activates timeshift, and seeks to (almost) the end
910 def activateTimeshiftEnd(self):
911 ts = self.getTimeshift()
916 if ts.isTimeshiftActive():
917 print "!! activate timeshift called - but shouldn't this be a normal pause?"
920 self.setSeekState(self.SEEK_STATE_PLAY)
921 ts.activateTimeshift()
924 # same as activateTimeshiftEnd, but pauses afterwards.
925 def activateTimeshiftEndAndPause(self):
926 state = self.seekstate
927 self.activateTimeshiftEnd()
929 # well, this is "andPause", but it could be pressed from pause,
930 # when pausing on the (fake-)"live" picture, so an un-pause
933 print "now, pauseService"
934 if state == self.SEEK_STATE_PLAY:
935 print "is PLAYING, start pause timer"
936 self.ts_pause_timer.start(200, 1)
939 self.unPauseService()
941 def __seekableStatusChanged(self):
944 print "self.isSeekable", self.isSeekable()
945 print "self.timeshift_enabled", self.timeshift_enabled
947 # when this service is not seekable, but timeshift
948 # is enabled, this means we can activate
950 if not self.isSeekable() and self.timeshift_enabled:
953 print "timeshift activate:", enabled
954 self["TimeshiftActivateActions"].setEnabled(enabled)
956 def __serviceStarted(self):
957 self.timeshift_enabled = False
958 self.__seekableStatusChanged()
960 from RecordTimer import parseEvent
962 class InfoBarInstantRecord:
963 """Instant Record - handles the instantRecord action in order to
964 start/stop instant records"""
966 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
968 "instantRecord": (self.instantRecord, "Instant Record..."),
971 self["BlinkingPoint"] = BlinkingPixmapConditional()
972 self["BlinkingPoint"].hide()
973 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
975 def stopCurrentRecording(self, entry = -1):
976 if entry is not None and entry != -1:
977 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
978 self.recording.remove(self.recording[entry])
980 def startInstantRecording(self, limitEvent = False):
981 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
983 # try to get event info
986 service = self.session.nav.getCurrentService()
987 epg = eEPGCache.getInstance()
988 event = epg.lookupEventTime(serviceref, -1, 0)
990 info = service.info()
991 ev = info.getEvent(0)
997 end = time.time() + 3600 * 10
998 name = "instant record"
1002 if event is not None:
1003 curEvent = parseEvent(event)
1005 description = curEvent[3]
1006 eventid = curEvent[4]
1011 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1013 data = (begin, end, name, description, eventid)
1015 recording = self.session.nav.recordWithTimer(serviceref, *data)
1016 recording.dontSave = True
1017 self.recording.append(recording)
1019 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1021 def isInstantRecordRunning(self):
1022 print "self.recording:", self.recording
1023 if len(self.recording) > 0:
1024 for x in self.recording:
1029 def recordQuestionCallback(self, answer):
1030 if answer is None or answer[1] == "no":
1033 for x in self.recording:
1035 list.append(TimerEntryComponent(x, False))
1037 if answer[1] == "changeduration":
1038 if len(self.recording) == 1:
1039 self.changeDuration(0)
1041 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1042 elif answer[1] == "stop":
1043 if len(self.recording) == 1:
1044 self.stopCurrentRecording(0)
1046 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1047 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1049 if answer[1] == "event":
1051 if answer[1] == "manualduration":
1052 self.selectedEntry = len(self.recording)
1053 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1054 self.startInstantRecording(limitEvent = limitEvent)
1056 def changeDuration(self, entry):
1057 if entry is not None:
1058 self.selectedEntry = entry
1059 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1061 def inputCallback(self, value):
1062 if value is not None:
1063 print "stopping recording after", int(value), "minutes."
1064 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1065 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1067 def instantRecord(self):
1069 stat = os.stat(resolveFilename(SCOPE_HDD))
1071 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1074 if self.isInstantRecordRunning():
1075 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")])
1077 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")])
1079 from Screens.AudioSelection import AudioSelection
1081 class InfoBarAudioSelection:
1083 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1085 "audioSelection": (self.audioSelection, "Audio Options..."),
1088 def audioSelection(self):
1089 service = self.session.nav.getCurrentService()
1090 audio = service.audioTracks()
1091 n = audio.getNumberOfTracks()
1093 self.session.open(AudioSelection, audio)
1095 from Screens.SubserviceSelection import SubserviceSelection
1097 class InfoBarSubserviceSelection:
1099 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1101 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1104 def subserviceSelection(self):
1105 service = self.session.nav.getCurrentService()
1106 subservices = service.subServices()
1107 n = subservices.getNumberOfSubservices()
1109 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1111 def subserviceSelected(self, service):
1112 if not service is None:
1113 self.session.nav.playService(service)
1115 class InfoBarAdditionalInfo:
1117 self["DolbyActive"] = Pixmap()
1118 self["CryptActive"] = Pixmap()
1119 self["FormatActive"] = Pixmap()
1121 self["ButtonRed"] = PixmapConditional(withTimer = False)
1122 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1123 self.onLayoutFinish.append(self["ButtonRed"].update)
1124 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1125 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1126 self.onLayoutFinish.append(self["ButtonRedText"].update)
1128 self["ButtonGreen"] = Pixmap()
1129 self["ButtonGreenText"] = Label(_("Subservices"))
1131 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1132 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1133 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1134 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1135 self.onLayoutFinish.append(self["ButtonYellow"].update)
1136 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1138 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1139 self["ButtonBlue"].setConnect(lambda: False)
1140 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1141 self["ButtonBlueText"].setConnect(lambda: False)
1142 self.onLayoutFinish.append(self["ButtonBlue"].update)
1143 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1145 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1147 def hideSubServiceIndication(self):
1148 self["ButtonGreen"].hide()
1149 self["ButtonGreenText"].hide()
1151 def showSubServiceIndication(self):
1152 self["ButtonGreen"].show()
1153 self["ButtonGreenText"].show()
1155 def checkFormat(self, service):
1156 info = service.info()
1157 if info is not None:
1158 aspect = info.getInfo(iServiceInformation.sAspect)
1159 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1160 self["FormatActive"].show()
1162 self["FormatActive"].hide()
1164 def checkSubservices(self, service):
1165 if service.subServices().getNumberOfSubservices() > 0:
1166 self.showSubServiceIndication()
1168 self.hideSubServiceIndication()
1170 def checkDolby(self, service):
1173 audio = service.audioTracks()
1174 if audio is not None:
1175 n = audio.getNumberOfTracks()
1177 i = audio.getTrackInfo(x)
1178 description = i.getDescription();
1179 if description.find("AC3") != -1 or description.find("DTS") != -1:
1183 self["DolbyActive"].show()
1185 self["DolbyActive"].hide()
1187 def checkCrypted(self, service):
1188 info = service.info()
1189 if info is not None:
1190 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1191 self["CryptActive"].show()
1193 self["CryptActive"].hide()
1195 def gotServiceEvent(self, ev):
1196 service = self.session.nav.getCurrentService()
1197 if ev == iPlayableService.evUpdatedEventInfo:
1198 self.checkSubservices(service)
1199 self.checkFormat(service)
1200 elif ev == iPlayableService.evUpdatedInfo:
1201 self.checkCrypted(service)
1202 self.checkDolby(service)
1203 elif ev == iPlayableService.evEnd:
1204 self.hideSubServiceIndication()
1205 self["CryptActive"].hide()
1206 self["DolbyActive"].hide()
1207 self["FormatActive"].hide()
1209 class InfoBarNotifications:
1211 self.onExecBegin.append(self.checkNotifications)
1212 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1214 def checkNotificationsIfExecing(self):
1216 self.checkNotifications()
1218 def checkNotifications(self):
1219 if len(Notifications.notifications):
1220 n = Notifications.notifications[0]
1221 Notifications.notifications = Notifications.notifications[1:]
1225 self.session.openWithCallback(cb, *n[1:])
1227 self.session.open(*n[1:])
1229 class InfoBarServiceNotifications:
1231 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1233 iPlayableService.evEnd: self.serviceHasEnded
1236 def serviceHasEnded(self):
1237 print "service end!"
1240 self.setSeekState(self.SEEK_STATE_PLAY)
1244 class InfoBarCueSheetSupport:
1250 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1252 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1253 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1254 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1258 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1260 iPlayableService.evStart: self.__serviceStarted,
1263 def __serviceStarted(self):
1264 print "new service started! trying to download cuts!"
1265 self.downloadCuesheet()
1267 def __getSeekable(self):
1268 service = self.session.nav.getCurrentService()
1271 return service.seek()
1273 def cueGetCurrentPosition(self):
1274 seek = self.__getSeekable()
1277 r = seek.getPlayPosition()
1282 def jumpPreviousNextMark(self, cmp, alternative=None):
1283 current_pos = self.cueGetCurrentPosition()
1284 if current_pos is None:
1286 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1287 if mark is not None:
1289 elif alternative is not None:
1294 seekable = self.__getSeekable()
1295 if seekable is not None:
1296 seekable.seekTo(pts)
1298 def jumpPreviousMark(self):
1299 # we add 2 seconds, so if the play position is <2s after
1300 # the mark, the mark before will be used
1301 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1303 def jumpNextMark(self):
1304 self.jumpPreviousNextMark(lambda x: x)
1306 def getNearestCutPoint(self, pts, cmp=abs):
1309 for cp in self.cut_list:
1310 diff = cmp(cp[0] - pts)
1311 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1315 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1316 current_pos = self.cueGetCurrentPosition()
1317 if current_pos is None:
1318 print "not seekable"
1321 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1323 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1325 return nearest_cutpoint
1327 self.removeMark(nearest_cutpoint)
1328 elif not onlyremove and not onlyreturn:
1329 self.addMark((current_pos, self.CUT_TYPE_MARK))
1334 def addMark(self, point):
1335 bisect.insort(self.cut_list, point)
1336 self.uploadCuesheet()
1338 def removeMark(self, point):
1339 self.cut_list.remove(point)
1340 self.uploadCuesheet()
1342 def __getCuesheet(self):
1343 service = self.session.nav.getCurrentService()
1346 return service.cueSheet()
1348 def uploadCuesheet(self):
1349 cue = self.__getCuesheet()
1352 print "upload failed, no cuesheet interface"
1354 cue.setCutList(self.cut_list)
1356 def downloadCuesheet(self):
1357 cue = self.__getCuesheet()
1360 print "upload failed, no cuesheet interface"
1362 self.cut_list = cue.getCutList()
1364 class InfoBarSummary(Screen):
1366 <screen position="0,0" size="132,64">
1367 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1368 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1371 def __init__(self, session, parent):
1372 Screen.__init__(self, session)
1373 self["CurrentService"] = ServiceName(self.session.nav)
1374 self["Clock"] = Clock()
1376 class InfoBarSummarySupport:
1380 def createSummary(self):
1381 return InfoBarSummary
1383 class InfoBarTeletextPlugin:
1385 self.teletext_plugin = None
1387 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1388 self.teletext_plugin = p
1390 if self.teletext_plugin is not None:
1391 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1393 "startTeletext": (self.startTeletext, "View teletext...")
1396 print "no teletext plugin found!"
1398 def startTeletext(self):
1399 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())