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 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 """
346 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
348 "showEventInfo": (self.openEventView, _("show EPG...")),
351 def zapToService(self, service):
352 if not service is None:
353 if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
354 self.servicelist.clearPath()
355 if self.servicelist.bouquet_root != self.epg_bouquet:
356 self.servicelist.enterPath(self.servicelist.bouquet_root)
357 self.servicelist.enterPath(self.epg_bouquet)
358 self.servicelist.setCurrentSelection(service) #select the service in servicelist
359 self.servicelist.zap()
361 def openBouquetEPG(self, bouquet, withCallback=True):
362 ptr=eEPGCache.getInstance()
364 servicelist = eServiceCenter.getInstance().list(bouquet)
365 if not servicelist is None:
367 service = servicelist.getNext()
368 if not service.valid(): #check if end of list
370 if service.flags: #ignore non playable services
372 services.append(ServiceReference(service))
374 self.epg_bouquet = bouquet
376 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService))
378 self.session.open(EPGSelection, services, self.zapToService)
380 def closed(self, ret=False):
383 dlgs=len(self.dlg_stack)
385 self.dlg_stack[dlgs-1].close(dlgs > 1)
387 def openMultiServiceEPG(self, withCallback=True):
388 bouquets = self.servicelist.getBouquetList()
393 if cnt > 1: # show bouquet list
395 self.dlg_stack.append(self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG))
397 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
399 self.openBouquetEPG(bouquets[0][1], withCallback)
401 def openSingleServiceEPG(self):
402 ref=self.session.nav.getCurrentlyPlayingServiceReference()
403 self.session.open(EPGSelection, ref)
405 def openSimilarList(self, eventid, refstr):
406 self.session.open(EPGSelection, refstr, None, eventid)
408 def openEventView(self):
410 service = self.session.nav.getCurrentService()
411 ref = self.session.nav.getCurrentlyPlayingServiceReference()
412 info = service.info()
415 self.epglist.append(ptr)
418 self.epglist.append(ptr)
419 if len(self.epglist) == 0:
420 epg = eEPGCache.getInstance()
421 ptr = epg.lookupEventTime(ref, -1)
423 self.epglist.append(ptr)
424 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
426 self.epglist.append(ptr)
427 if len(self.epglist) > 0:
428 self.dlg_stack.append(self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList))
430 print "no epg for the service avail.. so we show multiepg instead of eventinfo"
431 self.openMultiServiceEPG(False)
433 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
434 if len(self.epglist) > 1:
435 tmp = self.epglist[0]
436 self.epglist[0]=self.epglist[1]
438 setEvent(self.epglist[0])
441 """provides a snr/agc/ber display"""
443 self["snr"] = Label()
444 self["agc"] = Label()
445 self["ber"] = Label()
446 self["snr_percent"] = TunerInfo(TunerInfo.SNR_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
447 self["agc_percent"] = TunerInfo(TunerInfo.AGC_PERCENTAGE, servicefkt = self.session.nav.getCurrentService)
448 self["ber_count"] = TunerInfo(TunerInfo.BER_VALUE, servicefkt = self.session.nav.getCurrentService)
449 self["snr_progress"] = TunerInfo(TunerInfo.SNR_BAR, servicefkt = self.session.nav.getCurrentService)
450 self["agc_progress"] = TunerInfo(TunerInfo.AGC_BAR, servicefkt = self.session.nav.getCurrentService)
451 self["ber_progress"] = TunerInfo(TunerInfo.BER_BAR, servicefkt = self.session.nav.getCurrentService)
452 self.timer = eTimer()
453 self.timer.timeout.get().append(self.updateTunerInfo)
454 self.timer.start(1000)
456 def updateTunerInfo(self):
457 if self.instance.isVisible():
458 self["snr_percent"].update()
459 self["agc_percent"].update()
460 self["ber_count"].update()
461 self["snr_progress"].update()
462 self["agc_progress"].update()
463 self["ber_progress"].update()
466 """provides a current/next event info display"""
468 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
469 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
471 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
472 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
474 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
475 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
477 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
479 class InfoBarServiceName:
481 self["ServiceName"] = ServiceName(self.session.nav)
484 """handles actions like seeking, pause"""
486 # ispause, isff, issm
487 SEEK_STATE_PLAY = (0, 0, 0, ">")
488 SEEK_STATE_PAUSE = (1, 0, 0, "||")
489 SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
490 SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
491 SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
492 SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
493 SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
494 SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
496 SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
497 SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
498 SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
499 SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
501 SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
502 SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
503 SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
506 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
508 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
509 iPlayableService.evStart: self.__serviceStarted,
511 iPlayableService.evEOF: self.__evEOF,
512 iPlayableService.evSOF: self.__evSOF,
515 class InfoBarSeekActionMap(HelpableActionMap):
516 def __init__(self, screen, *args, **kwargs):
517 HelpableActionMap.__init__(self, screen, *args, **kwargs)
520 def action(self, contexts, action):
521 if action[:5] == "seek:":
522 time = int(action[5:])
523 self.screen.seekRelative(time * 90000)
526 return HelpableActionMap.action(self, contexts, action)
528 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions",
530 "pauseService": (self.pauseService, "pause"),
531 "unPauseService": (self.unPauseService, "continue"),
533 "seekFwd": (self.seekFwd, "skip forward"),
534 "seekFwdDown": self.seekFwdDown,
535 "seekFwdUp": self.seekFwdUp,
536 "seekBack": (self.seekBack, "skip backward"),
537 "seekBackDown": self.seekBackDown,
538 "seekBackUp": self.seekBackUp,
540 # give them a little more priority to win over color buttons
542 self.seekstate = self.SEEK_STATE_PLAY
543 self.onClose.append(self.delTimer)
545 self.fwdtimer = False
546 self.fwdKeyTimer = eTimer()
547 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
549 self.rwdtimer = False
550 self.rwdKeyTimer = eTimer()
551 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
553 self.onPlayStateChanged = [ ]
555 self.lockedBecauseOfSkipping = False
568 service = self.session.nav.getCurrentService()
572 seek = service.seek()
574 if seek is None or not seek.isCurrentlySeekable():
579 def isSeekable(self):
580 if self.getSeek() is None:
584 def __seekableStatusChanged(self):
585 print "seekable status changed!"
586 if not self.isSeekable():
587 self["SeekActions"].setEnabled(False)
588 print "not seekable, return to play"
589 self.setSeekState(self.SEEK_STATE_PLAY)
591 self["SeekActions"].setEnabled(True)
594 def __serviceStarted(self):
595 self.seekstate = self.SEEK_STATE_PLAY
597 def setSeekState(self, state):
598 service = self.session.nav.getCurrentService()
603 if not self.isSeekable():
604 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
605 state = self.SEEK_STATE_PLAY
607 pauseable = service.pause()
609 if pauseable is None:
610 print "not pauseable."
611 state = self.SEEK_STATE_PLAY
613 oldstate = self.seekstate
614 self.seekstate = state
617 if oldstate[i] != self.seekstate[i]:
618 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
620 for c in self.onPlayStateChanged:
623 self.checkSkipShowHideLock()
627 def pauseService(self):
628 if self.seekstate == self.SEEK_STATE_PAUSE:
629 print "pause, but in fact unpause"
630 self.unPauseService()
632 if self.seekstate == self.SEEK_STATE_PLAY:
633 print "yes, playing."
635 print "no", self.seekstate
637 self.setSeekState(self.SEEK_STATE_PAUSE);
639 def unPauseService(self):
641 self.setSeekState(self.SEEK_STATE_PLAY);
643 def doSeek(self, seektime):
644 print "doseek", seektime
645 service = self.session.nav.getCurrentService()
649 seekable = self.getSeek()
653 seekable.seekTo(90 * seektime)
655 def seekFwdDown(self):
656 print "start fwd timer"
658 self.fwdKeyTimer.start(1000)
660 def seekBackDown(self):
661 print "start rewind timer"
663 self.rwdKeyTimer.start(1000)
668 self.fwdKeyTimer.stop()
669 self.fwdtimer = False
674 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
675 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
676 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
677 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
678 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
679 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
680 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
681 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
682 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
683 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
684 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
685 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
686 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
687 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
688 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
690 self.setSeekState(lookup[self.seekstate])
692 def seekBackUp(self):
695 self.rwdKeyTimer.stop()
696 self.rwdtimer = False
701 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
702 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
703 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
704 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
705 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
706 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
707 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
708 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
709 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
710 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
711 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
712 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
713 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
714 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
715 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
717 self.setSeekState(lookup[self.seekstate])
719 if self.seekstate == self.SEEK_STATE_PAUSE:
720 seekable = self.getSeek()
721 if seekable is not None:
722 seekable.seekRelative(-1, 3)
724 def fwdTimerFire(self):
725 print "Display seek fwd"
726 self.fwdKeyTimer.stop()
727 self.fwdtimer = False
728 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
730 def fwdSeekTo(self, minutes):
731 print "Seek", minutes, "minutes forward"
733 seekable = self.getSeek()
734 if seekable is not None:
735 seekable.seekRelative(1, minutes * 60 * 90000)
737 def rwdTimerFire(self):
739 self.rwdKeyTimer.stop()
740 self.rwdtimer = False
741 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
743 def rwdSeekTo(self, minutes):
745 self.fwdSeekTo(0 - minutes)
747 def checkSkipShowHideLock(self):
748 wantlock = self.seekstate != self.SEEK_STATE_PLAY
750 if self.lockedBecauseOfSkipping and not wantlock:
752 self.lockedBecauseOfSkipping = False
754 if wantlock and not self.lockedBecauseOfSkipping:
756 self.lockedBecauseOfSkipping = True
759 if self.seekstate != self.SEEK_STATE_PLAY:
760 self.setSeekState(self.SEEK_STATE_PAUSE)
762 #self.getSeek().seekRelative(1, -90000)
763 self.setSeekState(self.SEEK_STATE_PLAY)
765 self.setSeekState(self.SEEK_STATE_PAUSE)
768 self.setSeekState(self.SEEK_STATE_PLAY)
771 def seekRelative(self, diff):
772 seekable = self.getSeek()
773 if seekable is not None:
774 seekable.seekRelative(1, diff)
776 from Screens.PVRState import PVRState, TimeshiftState
778 class InfoBarPVRState:
779 def __init__(self, screen=PVRState):
780 self.onPlayStateChanged.append(self.__playStateChanged)
781 self.pvrStateDialog = self.session.instantiateDialog(screen)
782 self.onShow.append(self.__mayShow)
783 self.onHide.append(self.pvrStateDialog.hide)
786 if self.seekstate != self.SEEK_STATE_PLAY and self.execing:
787 self.pvrStateDialog.show()
789 def __playStateChanged(self, state):
790 playstateString = state[3]
791 self.pvrStateDialog["state"].setText(playstateString)
794 class InfoBarTimeshiftState(InfoBarPVRState):
796 InfoBarPVRState.__init__(self, screen=TimeshiftState)
799 class InfoBarShowMovies:
801 # i don't really like this class.
802 # it calls a not further specified "movie list" on up/down/movieList,
803 # so this is not more than an action map
805 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
807 "movieList": (self.showMovies, "movie list"),
808 "up": (self.showMovies, "movie list"),
809 "down": (self.showMovies, "movie list")
812 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
816 # Timeshift works the following way:
817 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
818 # - normal playback TUNER unused PLAY enable disable disable
819 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
820 # - user presess pause again FILE record PLAY enable disable enable
821 # - user fast forwards FILE record FF enable disable enable
822 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
823 # - user backwards FILE record BACK # !! enable disable enable
827 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
828 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
829 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
830 # - the user can now PVR around
831 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
832 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
834 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
835 # - if the user rewinds, or press pause, timeshift will be activated again
837 # note that a timeshift can be enabled ("recording") and
838 # activated (currently time-shifting).
840 class InfoBarTimeshift:
842 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
844 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
845 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
847 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
849 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
850 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
851 }, prio=-1) # priority over record
853 self.timeshift_enabled = 0
854 self.timeshift_state = 0
855 self.ts_pause_timer = eTimer()
856 self.ts_pause_timer.timeout.get().append(self.pauseService)
858 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
860 iPlayableService.evStart: self.__serviceStarted,
861 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
864 def getTimeshift(self):
865 service = self.session.nav.getCurrentService()
866 return service and service.timeshift()
868 def startTimeshift(self):
869 print "enable timeshift"
870 ts = self.getTimeshift()
872 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
873 print "no ts interface"
876 if self.timeshift_enabled:
877 print "hu, timeshift already enabled?"
879 if not ts.startTimeshift():
881 self.timeshift_enabled = 1
882 self.pvrStateDialog["timeshift"].setRelative(time.time())
885 self.setSeekState(self.SEEK_STATE_PAUSE)
887 # enable the "TimeshiftEnableActions", which will override
888 # the startTimeshift actions
889 self.__seekableStatusChanged()
891 print "timeshift failed"
893 def stopTimeshift(self):
894 if not self.timeshift_enabled:
896 print "disable timeshift"
897 ts = self.getTimeshift()
900 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
902 def stopTimeshiftConfirmed(self, confirmed):
906 ts = self.getTimeshift()
911 self.timeshift_enabled = 0
914 self.__seekableStatusChanged()
916 # activates timeshift, and seeks to (almost) the end
917 def activateTimeshiftEnd(self):
918 ts = self.getTimeshift()
923 if ts.isTimeshiftActive():
924 print "!! activate timeshift called - but shouldn't this be a normal pause?"
927 self.setSeekState(self.SEEK_STATE_PLAY)
928 ts.activateTimeshift()
931 # same as activateTimeshiftEnd, but pauses afterwards.
932 def activateTimeshiftEndAndPause(self):
933 state = self.seekstate
934 self.activateTimeshiftEnd()
936 # well, this is "andPause", but it could be pressed from pause,
937 # when pausing on the (fake-)"live" picture, so an un-pause
940 print "now, pauseService"
941 if state == self.SEEK_STATE_PLAY:
942 print "is PLAYING, start pause timer"
943 self.ts_pause_timer.start(200, 1)
946 self.unPauseService()
948 def __seekableStatusChanged(self):
951 print "self.isSeekable", self.isSeekable()
952 print "self.timeshift_enabled", self.timeshift_enabled
954 # when this service is not seekable, but timeshift
955 # is enabled, this means we can activate
957 if not self.isSeekable() and self.timeshift_enabled:
960 print "timeshift activate:", enabled
961 self["TimeshiftActivateActions"].setEnabled(enabled)
963 def __serviceStarted(self):
964 self.timeshift_enabled = False
965 self.__seekableStatusChanged()
967 class InfoBarExtensions:
969 self.pipshown = False
971 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
973 #"extensions": (self.extensions, "Extensions..."),
976 def extensions(self):
978 if self.pipshown == False:
979 list.append((_("Activate Picture in Picture"), "pipon"))
980 elif self.pipshown == True:
981 list.append((_("Disable Picture in Picture"), "pipoff"))
982 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list)
984 def extensionCallback(self, answer):
985 if answer is not None:
986 if answer[1] == "pipon":
987 self.session.nav.stopService()
988 self.pip = self.session.instantiateDialog(PictureInPicture)
991 newservice = self.session.nav.getCurrentlyPlayingServiceReference()
992 self.pipservice = eServiceCenter.getInstance().play(newservice)
993 if self.pipservice and not self.pipservice.setTarget(1):
994 self.pipservice.start()
997 self.pipservice = None
1000 elif answer[1] == "pipoff":
1002 self.pipservice = None
1004 self.pipshown = False
1006 from RecordTimer import parseEvent
1008 class InfoBarInstantRecord:
1009 """Instant Record - handles the instantRecord action in order to
1010 start/stop instant records"""
1012 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1014 "instantRecord": (self.instantRecord, "Instant Record..."),
1017 self["BlinkingPoint"] = BlinkingPixmapConditional()
1018 self["BlinkingPoint"].hide()
1019 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1021 def stopCurrentRecording(self, entry = -1):
1022 if entry is not None and entry != -1:
1023 self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1024 self.recording.remove(self.recording[entry])
1026 def startInstantRecording(self, limitEvent = False):
1027 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1029 # try to get event info
1032 service = self.session.nav.getCurrentService()
1033 epg = eEPGCache.getInstance()
1034 event = epg.lookupEventTime(serviceref, -1, 0)
1036 info = service.info()
1037 ev = info.getEvent(0)
1043 end = time.time() + 3600 * 10
1044 name = "instant record"
1048 if event is not None:
1049 curEvent = parseEvent(event)
1051 description = curEvent[3]
1052 eventid = curEvent[4]
1057 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1059 data = (begin, end, name, description, eventid)
1061 recording = self.session.nav.recordWithTimer(serviceref, *data)
1062 recording.dontSave = True
1063 self.recording.append(recording)
1065 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1067 def isInstantRecordRunning(self):
1068 print "self.recording:", self.recording
1069 if len(self.recording) > 0:
1070 for x in self.recording:
1075 def recordQuestionCallback(self, answer):
1076 print "pre:\n", self.recording
1078 if answer is None or answer[1] == "no":
1081 recording = self.recording[:]
1083 if not x in self.session.nav.RecordTimer.timer_list:
1084 self.recording.remove(x)
1085 elif x.dontSave and x.isRunning():
1086 list.append(TimerEntryComponent(x, False))
1088 if answer[1] == "changeduration":
1089 if len(self.recording) == 1:
1090 self.changeDuration(0)
1092 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1093 elif answer[1] == "stop":
1094 if len(self.recording) == 1:
1095 self.stopCurrentRecording(0)
1097 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1098 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1100 if answer[1] == "event":
1102 if answer[1] == "manualduration":
1103 self.selectedEntry = len(self.recording)
1104 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1105 self.startInstantRecording(limitEvent = limitEvent)
1107 print "after:\n", self.recording
1109 def changeDuration(self, entry):
1110 if entry is not None:
1111 self.selectedEntry = entry
1112 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1114 def inputCallback(self, value):
1115 if value is not None:
1116 print "stopping recording after", int(value), "minutes."
1117 self.recording[self.selectedEntry].end = time.time() + 60 * int(value)
1118 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1120 def instantRecord(self):
1122 stat = os.stat(resolveFilename(SCOPE_HDD))
1124 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1127 if self.isInstantRecordRunning():
1128 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")])
1130 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")])
1132 from Screens.AudioSelection import AudioSelection
1134 class InfoBarAudioSelection:
1136 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1138 "audioSelection": (self.audioSelection, "Audio Options..."),
1141 def audioSelection(self):
1142 service = self.session.nav.getCurrentService()
1143 audio = service.audioTracks()
1144 n = audio.getNumberOfTracks()
1146 self.session.open(AudioSelection, audio)
1148 from Screens.SubserviceSelection import SubserviceSelection
1150 class InfoBarSubserviceSelection:
1152 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1154 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1157 def subserviceSelection(self):
1158 service = self.session.nav.getCurrentService()
1159 subservices = service.subServices()
1160 n = subservices.getNumberOfSubservices()
1162 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1164 def subserviceSelected(self, service):
1165 if not service is None:
1166 self.session.nav.playService(service)
1168 class InfoBarAdditionalInfo:
1170 self["DolbyActive"] = Pixmap()
1171 self["CryptActive"] = Pixmap()
1172 self["FormatActive"] = Pixmap()
1174 self["ButtonRed"] = PixmapConditional(withTimer = False)
1175 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1176 self.onLayoutFinish.append(self["ButtonRed"].update)
1177 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1178 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1179 self.onLayoutFinish.append(self["ButtonRedText"].update)
1181 self["ButtonGreen"] = Pixmap()
1182 self["ButtonGreenText"] = Label(_("Subservices"))
1184 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1185 self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1186 self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
1187 self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1188 self.onLayoutFinish.append(self["ButtonYellow"].update)
1189 self.onLayoutFinish.append(self["ButtonYellowText"].update)
1191 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1192 self["ButtonBlue"].setConnect(lambda: False)
1193 self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
1194 self["ButtonBlueText"].setConnect(lambda: False)
1195 self.onLayoutFinish.append(self["ButtonBlue"].update)
1196 self.onLayoutFinish.append(self["ButtonBlueText"].update)
1198 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1200 def hideSubServiceIndication(self):
1201 self["ButtonGreen"].hide()
1202 self["ButtonGreenText"].hide()
1204 def showSubServiceIndication(self):
1205 self["ButtonGreen"].show()
1206 self["ButtonGreenText"].show()
1208 def checkFormat(self, service):
1209 info = service.info()
1210 if info is not None:
1211 aspect = info.getInfo(iServiceInformation.sAspect)
1212 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1213 self["FormatActive"].show()
1215 self["FormatActive"].hide()
1217 def checkSubservices(self, service):
1218 if service.subServices().getNumberOfSubservices() > 0:
1219 self.showSubServiceIndication()
1221 self.hideSubServiceIndication()
1223 def checkDolby(self, service):
1226 audio = service.audioTracks()
1227 if audio is not None:
1228 n = audio.getNumberOfTracks()
1230 i = audio.getTrackInfo(x)
1231 description = i.getDescription();
1232 if description.find("AC3") != -1 or description.find("DTS") != -1:
1236 self["DolbyActive"].show()
1238 self["DolbyActive"].hide()
1240 def checkCrypted(self, service):
1241 info = service.info()
1242 if info is not None:
1243 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1244 self["CryptActive"].show()
1246 self["CryptActive"].hide()
1248 def gotServiceEvent(self, ev):
1249 service = self.session.nav.getCurrentService()
1250 if ev == iPlayableService.evUpdatedEventInfo:
1251 self.checkSubservices(service)
1252 self.checkFormat(service)
1253 elif ev == iPlayableService.evUpdatedInfo:
1254 self.checkCrypted(service)
1255 self.checkDolby(service)
1256 elif ev == iPlayableService.evEnd:
1257 self.hideSubServiceIndication()
1258 self["CryptActive"].hide()
1259 self["DolbyActive"].hide()
1260 self["FormatActive"].hide()
1262 class InfoBarNotifications:
1264 self.onExecBegin.append(self.checkNotifications)
1265 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1267 def checkNotificationsIfExecing(self):
1269 self.checkNotifications()
1271 def checkNotifications(self):
1272 if len(Notifications.notifications):
1273 n = Notifications.notifications[0]
1274 Notifications.notifications = Notifications.notifications[1:]
1278 self.session.openWithCallback(cb, *n[1:])
1280 self.session.open(*n[1:])
1282 class InfoBarServiceNotifications:
1284 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1286 iPlayableService.evEnd: self.serviceHasEnded
1289 def serviceHasEnded(self):
1290 print "service end!"
1293 self.setSeekState(self.SEEK_STATE_PLAY)
1297 class InfoBarCueSheetSupport:
1303 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
1305 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1306 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1307 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1311 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1313 iPlayableService.evStart: self.__serviceStarted,
1316 def __serviceStarted(self):
1317 print "new service started! trying to download cuts!"
1318 self.downloadCuesheet()
1320 def __getSeekable(self):
1321 service = self.session.nav.getCurrentService()
1324 return service.seek()
1326 def cueGetCurrentPosition(self):
1327 seek = self.__getSeekable()
1330 r = seek.getPlayPosition()
1335 def jumpPreviousNextMark(self, cmp, alternative=None):
1336 current_pos = self.cueGetCurrentPosition()
1337 if current_pos is None:
1339 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1340 if mark is not None:
1342 elif alternative is not None:
1347 seekable = self.__getSeekable()
1348 if seekable is not None:
1349 seekable.seekTo(pts)
1351 def jumpPreviousMark(self):
1352 # we add 2 seconds, so if the play position is <2s after
1353 # the mark, the mark before will be used
1354 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1356 def jumpNextMark(self):
1357 self.jumpPreviousNextMark(lambda x: x)
1359 def getNearestCutPoint(self, pts, cmp=abs):
1362 for cp in self.cut_list:
1363 diff = cmp(cp[0] - pts)
1364 if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1368 def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1369 current_pos = self.cueGetCurrentPosition()
1370 if current_pos is None:
1371 print "not seekable"
1374 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1376 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1378 return nearest_cutpoint
1380 self.removeMark(nearest_cutpoint)
1381 elif not onlyremove and not onlyreturn:
1382 self.addMark((current_pos, self.CUT_TYPE_MARK))
1387 def addMark(self, point):
1388 bisect.insort(self.cut_list, point)
1389 self.uploadCuesheet()
1391 def removeMark(self, point):
1392 self.cut_list.remove(point)
1393 self.uploadCuesheet()
1395 def __getCuesheet(self):
1396 service = self.session.nav.getCurrentService()
1399 return service.cueSheet()
1401 def uploadCuesheet(self):
1402 cue = self.__getCuesheet()
1405 print "upload failed, no cuesheet interface"
1407 cue.setCutList(self.cut_list)
1409 def downloadCuesheet(self):
1410 cue = self.__getCuesheet()
1413 print "upload failed, no cuesheet interface"
1415 self.cut_list = cue.getCutList()
1417 class InfoBarSummary(Screen):
1419 <screen position="0,0" size="132,64">
1420 <widget name="Clock" position="50,46" size="82,18" font="Regular;16" />
1421 <widget name="CurrentService" position="0,4" size="132,42" font="Regular;18" />
1424 def __init__(self, session, parent):
1425 Screen.__init__(self, session)
1426 self["CurrentService"] = ServiceName(self.session.nav)
1427 self["Clock"] = Clock()
1429 class InfoBarSummarySupport:
1433 def createSummary(self):
1434 return InfoBarSummary
1436 class InfoBarTeletextPlugin:
1438 self.teletext_plugin = None
1440 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1441 self.teletext_plugin = p
1443 if self.teletext_plugin is not None:
1444 self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1446 "startTeletext": (self.startTeletext, "View teletext...")
1449 print "no teletext plugin found!"
1451 def startTeletext(self):
1452 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())