# -*- coding: utf-8 -*- from Components.ActionMap import ActionMap, HelpableActionMap, HelpableNumberActionMap, NumberActionMap from Components.Harddisk import harddiskmanager, findMountPoint from Components.Input import Input from Components.Label import Label from Components.MovieList import AUDIO_EXTENSIONS, MOVIE_EXTENSIONS, DVD_EXTENSIONS from Components.PluginComponent import plugins from Components.ServiceEventTracker import ServiceEventTracker from Components.Sources.ServiceEvent import ServiceEvent from Components.Sources.Boolean import Boolean from Components.config import config, configfile, ConfigBoolean, ConfigClock, ConfigSelection from Components.SystemInfo import SystemInfo from Components.UsageConfig import preferredInstantRecordPath, defaultMoviePath from Components.VolumeControl import VolumeControl from Components.Pixmap import MovingPixmap, MultiPixmap from Components.Sources.StaticText import StaticText from Components.ScrollLabel import ScrollLabel from Plugins.Plugin import PluginDescriptor from Components.Timeshift import InfoBarTimeshift from Screens.Screen import Screen from Screens.HelpMenu import HelpableScreen from Screens import ScreenSaver from Screens.ChannelSelection import ChannelSelection, PiPZapSelection, BouquetSelector, EpgBouquetSelector, service_types_tv from Screens.ChoiceBox import ChoiceBox from Screens.Dish import Dish from Screens.EventView import EventViewEPGSelect, EventViewSimple from Screens.EpgSelectionGrid import EPGSelectionGrid from Screens.EpgSelectionInfobarGrid import EPGSelectionInfobarGrid from Screens.EpgSelectionInfobarSingle import EPGSelectionInfobarSingle from Screens.EpgSelectionMulti import EPGSelectionMulti from Screens.EpgSelectionSimilar import EPGSelectionSimilar from Screens.EpgSelectionSingle import EPGSelectionSingle from Screens.InputBox import InputBox from Screens.MessageBox import MessageBox from Screens.MinuteInput import MinuteInput from Screens.TimerSelection import TimerSelection from Screens.PictureInPicture import PictureInPicture from Screens.PVRState import PVRState, TimeshiftState from Screens.SubtitleDisplay import SubtitleDisplay from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive from Screens.TimeDateInput import TimeDateInput from Screens.TimerEdit import TimerEditList from Screens.TimerEntry import TimerEntry, addTimerFromEvent from Screens.UnhandledKey import UnhandledKey from ServiceReference import ServiceReference, isPlayableForCur from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT, findSafeRecordPath from Tools import Notifications from Tools.Directories import pathExists, fileExists from Tools.KeyBindings import getKeyDescription, getKeyBindingKeys import NavigationInstance from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, iPlayableService, iRecordableService, eServiceReference, eEPGCache, eActionMap, getDesktop, eDVBDB from keyids import KEYFLAGS, KEYIDS, invertKeyIds from time import time, localtime, strftime from bisect import insort from sys import maxint import itertools import datetime import os import cPickle # hack alert! from Screens.Menu import MainMenu, Menu, mdom from Screens.Setup import Setup import Screens.Standby def isStandardInfoBar(self): return self.__class__.__name__ == "InfoBar" def isMoviePlayerInfoBar(self): return self.__class__.__name__ == "MoviePlayer" def setResumePoint(session): global resumePointCache, resumePointCacheLast service = session.nav.getCurrentService() ref = session.nav.getCurrentlyPlayingServiceOrGroup() if (service is not None) and (ref is not None): # and (ref.type != 1): # ref type 1 has its own memory... seek = service.seek() if seek: pos = seek.getPlayPosition() if not pos[0]: key = ref.toString() lru = int(time()) l = seek.getLength() if l: l = l[1] else: l = None resumePointCache[key] = [lru, pos[1], l] for k, v in resumePointCache.items(): if v[0] < lru: candidate = k filepath = os.path.realpath(candidate.split(':')[-1]) mountpoint = findMountPoint(filepath) if os.path.ismount(mountpoint) and not os.path.exists(filepath): del resumePointCache[candidate] saveResumePoints() def delResumePoint(ref): global resumePointCache, resumePointCacheLast try: del resumePointCache[ref.toString()] except KeyError: pass saveResumePoints() def getResumePoint(session): global resumePointCache ref = session.nav.getCurrentlyPlayingServiceOrGroup() if (ref is not None) and (ref.type != 1): try: entry = resumePointCache[ref.toString()] entry[0] = int(time()) # update LRU timestamp return entry[1] except KeyError: return None def saveResumePoints(): global resumePointCache, resumePointCacheLast try: f = open('/etc/enigma2/resumepoints.pkl', 'wb') cPickle.dump(resumePointCache, f, cPickle.HIGHEST_PROTOCOL) f.close() except Exception, ex: print "[InfoBarGenerics] Failed to write resumepoints:", ex resumePointCacheLast = int(time()) def loadResumePoints(): try: file = open('/etc/enigma2/resumepoints.pkl', 'rb') PickleFile = cPickle.load(file) file.close() return PickleFile except Exception, ex: print "[InfoBarGenerics] Failed to load resumepoints:", ex return {} def updateresumePointCache(): global resumePointCache resumePointCache = loadResumePoints() resumePointCache = loadResumePoints() resumePointCacheLast = int(time()) whitelist_vbi = None def reload_whitelist_vbi(): global whitelist_vbi whitelist_vbi = [line.strip() for line in open('/etc/enigma2/whitelist_vbi', 'r').readlines()] if os.path.isfile('/etc/enigma2/whitelist_vbi') else [] reload_whitelist_vbi() subservice_groupslist = None def reload_subservice_groupslist(force=False): global subservice_groupslist if subservice_groupslist is None or force: try: groupedservices = "/etc/enigma2/groupedservices" if not os.path.isfile(groupedservices): groupedservices = "/usr/share/enigma2/groupedservices" subservice_groupslist = [list(g) for k, g in itertools.groupby([line.split('#')[0].strip() for line in open(groupedservices).readlines()], lambda x:not x) if not k] except: subservice_groupslist = [] reload_subservice_groupslist() def getPossibleSubservicesForCurrentChannel(current_service): if current_service and subservice_groupslist: ref_in_subservices_group = [x for x in subservice_groupslist if current_service in x] if ref_in_subservices_group: return ref_in_subservices_group[0] return [] def getActiveSubservicesForCurrentChannel(current_service): if current_service: possibleSubservices = getPossibleSubservicesForCurrentChannel(current_service) activeSubservices = [] epgCache = eEPGCache.getInstance() idx = 0 for subservice in possibleSubservices: events = epgCache.lookupEvent(['BDTS', (subservice, 0, -1)]) if events and len(events) == 1: event = events[0] title = event[2] if title and "Sendepause" not in title: starttime = datetime.datetime.fromtimestamp(event[0]).strftime('%H:%M') endtime = datetime.datetime.fromtimestamp(event[0] + event[1]).strftime('%H:%M') current_show_name = title + " " + str(starttime) + "-" + str(endtime) activeSubservices.append((current_show_name, subservice)) return activeSubservices def hasActiveSubservicesForCurrentChannel(current_service): activeSubservices = getActiveSubservicesForCurrentChannel(current_service) return bool(activeSubservices and len(activeSubservices) > 1) class InfoBarDish: def __init__(self): self.dishDialog = self.session.instantiateDialog(Dish) self.dishDialog.setAnimationMode(0) self.onClose.append(self.__onClose) def __onClose(self): if self.dishDialog: self.dishDialog.doClose() self.dishDialog = None class InfoBarLongKeyDetection: def __init__(self): eActionMap.getInstance().bindAction("", -maxint - 1, self.detection) # Highest priority. self.LongButtonPressed = False def detection(self, key, flag): # This function is called on every keypress! if flag == 3: self.LongButtonPressed = True elif flag == 0: self.LongButtonPressed = False class InfoBarUnhandledKey: def __init__(self): self.unhandledKeyDialog = self.session.instantiateDialog(UnhandledKey) self.unhandledKeyDialog.setAnimationMode(0) self.hideUnhandledKeySymbolTimer = eTimer() self.hideUnhandledKeySymbolTimer.callback.append(self.unhandledKeyDialog.hide) self.checkUnusedTimer = eTimer() self.checkUnusedTimer.callback.append(self.checkUnused) self.onLayoutFinish.append(self.unhandledKeyDialog.hide) eActionMap.getInstance().bindAction("", -maxint - 1, self.actionA) # Highest priority. eActionMap.getInstance().bindAction("", maxint, self.actionB) # Lowest priority. self.flags = (1 << 1) self.uflags = 0 self.invKeyIds = invertKeyIds() self.sibIgnoreKeys = ( KEYIDS["KEY_VOLUMEDOWN"], KEYIDS["KEY_VOLUMEUP"], KEYIDS["KEY_OK"], KEYIDS["KEY_UP"], KEYIDS["KEY_DOWN"], KEYIDS["KEY_CHANNELUP"], KEYIDS["KEY_CHANNELDOWN"], KEYIDS["KEY_NEXT"], KEYIDS["KEY_PREVIOUS"] ) self.onClose.append(self.__onClose) def __onClose(self): eActionMap.getInstance().unbindAction('', self.actionA) eActionMap.getInstance().unbindAction('', self.actionB) if self.unhandledKeyDialog: self.unhandledKeyDialog.doClose() self.unhandledKeyDialog = None def actionA(self, key, flag): # This function is called on every keypress! print "[InfoBarGenerics] Key: %s (%s) KeyID='%s' Binding='%s'." % (key, KEYFLAGS[flag], self.invKeyIds.get(key, ""), getKeyDescription(key)) if flag != 2: # don't hide on repeat self.unhandledKeyDialog.hide() if self.closeSIB(key) and self.secondInfoBarScreen and self.secondInfoBarScreen.shown: self.secondInfoBarScreen.hide() self.secondInfoBarWasShown = False if flag != 4: if flag == 0: self.flags = self.uflags = 0 self.flags |= (1 << flag) if flag == 1 or flag == 3: # Break and Long self.checkUnusedTimer.start(0, True) return 0 def closeSIB(self, key): return True if key >= 12 and key not in self.sibIgnoreKeys else False # (114, 115, 352, 103, 108, 402, 403, 407, 412) def actionB(self, key, flag): # This function is only called when no other action has handled this key. if flag != 4: self.uflags |= (1 << flag) def checkUnused(self): if self.flags == self.uflags: self.unhandledKeyDialog.show() self.hideUnhandledKeySymbolTimer.start(2000, True) class InfoBarScreenSaver: def __init__(self): self.onExecBegin.append(self.__onExecBegin) self.onExecEnd.append(self.__onExecEnd) self.screenSaverTimer = eTimer() self.screenSaverTimer.callback.append(self.screensaverTimeout) self.screensaver = self.session.instantiateDialog(ScreenSaver.Screensaver) self.onClose.append(self.__onClose) self.onLayoutFinish.append(self.__layoutFinished) def __onClose(self): if self.screensaver: self.screensaver.doClose() self.screensaver = None def __layoutFinished(self): self.screensaver.hide() def __onExecBegin(self): self.ScreenSaverTimerStart() def __onExecEnd(self): if self.screensaver.shown: self.screensaver.hide() eActionMap.getInstance().unbindAction('', self.keypressScreenSaver) self.screenSaverTimer.stop() def ScreenSaverTimerStart(self): time = int(config.usage.screen_saver.value) flag = self.seekstate[0] if not flag: ref = self.session.nav.getCurrentlyPlayingServiceOrGroup() if ref and not (hasattr(self.session, "pipshown") and self.session.pipshown): ref = ref.toString().split(":") flag = ref[2] == "2" or os.path.splitext(ref[10])[1].lower() in AUDIO_EXTENSIONS if time and flag: self.screenSaverTimer.startLongTimer(time) else: self.screenSaverTimer.stop() def screensaverTimeout(self): if self.execing and not Screens.Standby.inStandby and not Screens.Standby.inTryQuitMainloop: self.hide() if hasattr(self, "pvrStateDialog"): self.pvrStateDialog.hide() self.screensaver.show() eActionMap.getInstance().bindAction('', -maxint - 1, self.keypressScreenSaver) def keypressScreenSaver(self, key, flag): if flag: self.screensaver.hide() self.show() self.ScreenSaverTimerStart() eActionMap.getInstance().unbindAction('', self.keypressScreenSaver) class HideVBILine(Screen): def __init__(self, session): self.skin = """""" % (getDesktop(0).size().width(), getDesktop(0).size().height() / 360 + 1) Screen.__init__(self, session) class SecondInfoBar(Screen, HelpableScreen): ADD_TIMER = 0 REMOVE_TIMER = 1 def __init__(self, session): Screen.__init__(self, session) if config.usage.second_infobar_simple.value: self.skinName = ["SecondInfoBarSimple", "SecondInfoBar"] HelpableScreen.__init__(self) self["epg_description"] = ScrollLabel() self["channel"] = Label() self["key_red"] = Label() self["key_green"] = Label() self["key_yellow"] = Label() self["key_blue"] = Label() self["SecondInfoBar"] = HelpableActionMap(self, ["2ndInfobarActions"], { "prevPage": (self.pageUp, _("Page up in description")), "nextPage": (self.pageDown, _("Page down in description")), "prevEvent": (self.prevEvent, _("Show description for previous event)")), "nextEvent": (self.nextEvent, _("Show description for next event)")), "timerAdd": (self.timerAdd, _("Add timer")), "openSimilarList": (self.openSimilarList, _("Show list of similar programs")), }, prio=-1, description=_("Second infobar")) self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evUpdatedEventInfo: self.getEvent }) self.onShow.append(self.__Show) self.onHide.append(self.__Hide) def pageUp(self): self["epg_description"].pageUp() def pageDown(self): self["epg_description"].pageDown() def __Show(self): if config.vixsettings.ColouredButtons.value: self["key_yellow"].setText(_("Search")) self["key_red"].setText(_("Similar")) self["key_blue"].setText(_("Extensions")) self["SecondInfoBar"].doBind() self.getEvent() def __Hide(self): if self["SecondInfoBar"].bound: self["SecondInfoBar"].doUnbind() def getEvent(self): self["epg_description"].setText("") self["channel"].setText("") ref = self.session.nav.getCurrentlyPlayingServiceOrGroup() self.getNowNext() epglist = self.epglist if not epglist: self.is_now_next = False epg = eEPGCache.getInstance() ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1) if ptr: epglist.append(ptr) ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1) if ptr: epglist.append(ptr) else: self.is_now_next = True if epglist: Event = self.epglist[0] Ref = ServiceReference(ref) callback = self.eventViewCallback self.cbFunc = callback self.currentService = Ref self.isRecording = (not Ref.ref.flags & eServiceReference.isGroup) and Ref.ref.getPath() self.event = Event self.key_green_choice = self.ADD_TIMER if self.isRecording: self["key_green"].setText("") else: self["key_green"].setText(_("Add timer")) self.setEvent(self.event) def getNowNext(self): epglist = [] service = self.session.nav.getCurrentService() info = service and service.info() ptr = info and info.getEvent(0) if ptr: epglist.append(ptr) ptr = info and info.getEvent(1) if ptr: epglist.append(ptr) self.epglist = epglist def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying epglist = self.epglist if len(epglist) > 1: tmp = epglist[0] epglist[0] = epglist[1] epglist[1] = tmp setEvent(epglist[0]) def prevEvent(self): if self.cbFunc is not None: self.cbFunc(self.setEvent, self.setService, -1) def nextEvent(self): if self.cbFunc is not None: self.cbFunc(self.setEvent, self.setService, +1) def removeTimer(self, timer): timer.afterEvent = AFTEREVENT.NONE self.session.nav.RecordTimer.removeEntry(timer) self["key_green"].setText(_("Add timer")) self.key_green_choice = self.ADD_TIMER def timerAdd(self): self.hide() self.secondInfoBarWasShown = False if self.isRecording: return event = self.event serviceref = self.currentService if event is None: return eventid = event.getEventId() refstr = serviceref.toString() for timer in self.session.nav.RecordTimer.timer_list: if timer.eit == eventid and timer.service_ref.toString() == refstr: cb_func = lambda ret: not ret or self.removeTimer(timer) self.session.openWithCallback(cb_func, MessageBox, _("Do you really want to delete %s?") % event.getEventName(), simple=True) break else: def refreshButtons(timer): if timer: self["key_green"].setText(_("Remove timer")) self.key_green_choice = self.REMOVE_TIMER else: self["key_green"].setText(_("Add timer")) self.key_green_choice = self.ADD_TIMER addTimerFromEvent(self.session, refreshButtons, event, serviceref) def setService(self, service): self.currentService = service if self.isRecording: self["channel"].setText(_("Recording")) else: name = self.currentService.getServiceName() if name is not None: self["channel"].setText(name) else: self["channel"].setText(_("unknown service")) def sort_func(self, x, y): if x[1] < y[1]: return -1 elif x[1] == y[1]: return 0 else: return 1 def setEvent(self, event): if event is None: return self.event = event try: name = event.getEventName() self["channel"].setText(name) except: pass description = event.getShortDescription() extended = event.getExtendedDescription() if description and extended: description += '\n' text = description + extended self.setTitle(event.getEventName()) self["epg_description"].setText(text) serviceref = self.currentService eventid = self.event.getEventId() refstr = serviceref.ref.toString() isRecordEvent = False for timer in self.session.nav.RecordTimer.timer_list: if timer.eit == eventid and timer.service_ref.ref.toString() == refstr: isRecordEvent = True break if isRecordEvent and self.key_green_choice != self.REMOVE_TIMER: self["key_green"].setText(_("Remove timer")) self.key_green_choice = self.REMOVE_TIMER elif not isRecordEvent and self.key_green_choice != self.ADD_TIMER: self["key_green"].setText(_("Add timer")) self.key_green_choice = self.ADD_TIMER def openSimilarList(self): id = self.event and self.event.getEventId() refstr = str(self.currentService) if id is not None: self.hide() self.secondInfoBarWasShown = False self.session.open(EPGSelectionSimilar, refstr, id) class InfoBarShowHide(InfoBarScreenSaver): """ InfoBar show/hide control, accepts toggleShow and hide actions, might start fancy animations. """ STATE_HIDDEN = 0 STATE_HIDING = 1 STATE_SHOWING = 2 STATE_SHOWN = 3 FLAG_CENTER_DVB_SUBS = 2048 def __init__(self): self["ShowHideActions"] = HelpableActionMap(self, ["InfobarShowHideActions"], { "LongOKPressed": (self.toggleShowLong, self._helpToggleShowLong), "toggleShow": (self.toggleShow, _("Cycle through infobar displays")), "hide": (self.keyHide, self._helpKeyHide), }, prio=1, description=_("Show/hide infobar")) # lower prio to make it possible to override ok and cancel.. self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evStart: self.serviceStarted, }) InfoBarScreenSaver.__init__(self) self.__state = self.STATE_SHOWN self.__locked = 0 self.hideTimer = eTimer() self.hideTimer.callback.append(self.doTimerHide) self.hideTimer.start(5000, True) self.onShow.append(self.__onShow) self.onHide.append(self.__onHide) self.onShowHideNotifiers = [] self.standardInfoBar = False self.lastResetAlpha = True self.secondInfoBarScreen = "" if isStandardInfoBar(self): self.secondInfoBarScreen = self.session.instantiateDialog(SecondInfoBar) self.secondInfoBarScreen.show() from Screens.InfoBar import InfoBar InfoBarInstance = InfoBar.instance if InfoBarInstance: InfoBarInstance.hideVBILineScreen.hide() self.hideVBILineScreen = self.session.instantiateDialog(HideVBILine) self.hideVBILineScreen.show() self.onClose.append(self.__onClose) self.onLayoutFinish.append(self.__layoutFinished) self.onExecBegin.append(self.__onExecBegin) def __onClose(self): if self.hideVBILineScreen: self.hideVBILineScreen.doClose() self.hideVBILineScreen = None def __onExecBegin(self): self.showHideVBI() def __layoutFinished(self): if self.secondInfoBarScreen: self.secondInfoBarScreen.hide() self.standardInfoBar = True self.secondInfoBarWasShown = False self.hideVBILineScreen.hide() self.EventViewIsShown = False def __onShow(self): self.__state = self.STATE_SHOWN for x in self.onShowHideNotifiers: x(True) self.startHideTimer() VolumeControl.instance and VolumeControl.instance.showMute() def doDimming(self): if config.usage.show_infobar_do_dimming.value: self.dimmed = self.dimmed - 1 else: self.dimmed = 0 self.DimmingTimer.stop() self.doHide() def unDimming(self): self.unDimmingTimer.stop() self.doWriteAlpha(config.av.osd_alpha.value) def doWriteAlpha(self, value): if fileExists("/proc/stb/video/alpha"): f = open("/proc/stb/video/alpha", "w") f.write("%i" % (value)) f.close() if value == config.av.osd_alpha.value: self.lastResetAlpha = True else: self.lastResetAlpha = False def __onHide(self): self.__state = self.STATE_HIDDEN self.resetAlpha() for x in self.onShowHideNotifiers: x(False) def resetAlpha(self): if config.usage.show_infobar_do_dimming.value and self.lastResetAlpha is False: self.unDimmingTimer = eTimer() self.unDimmingTimer.callback.append(self.unDimming) self.unDimmingTimer.start(300, True) def _helpKeyHide(self): if self.__state == self.STATE_HIDDEN: if config.vixsettings.InfoBarEpg_mode.value == "2": return _("Show infobar EPG") else: return { "no": _("Hide infobar display"), "popup": _("Hide infobar display and ask whether to close PiP") if self.session.pipshown else _("Ask whether to stop movie"), "without popup": _("Hide infobar display and close PiP") if self.session.pipshown else _("Stop movie") }.get(config.usage.pip_hideOnExit.value, _("No current function")) else: return _("Hide infobar display") def keyHide(self): if self.__state == self.STATE_HIDDEN: if config.vixsettings.InfoBarEpg_mode.value == "2": self.openInfoBarEPG() else: self.hide() if self.secondInfoBarScreen and self.secondInfoBarScreen.shown: self.secondInfoBarScreen.hide() self.secondInfoBarWasShown = False if self.session.pipshown and "popup" in config.usage.pip_hideOnExit.value: if config.usage.pip_hideOnExit.value == "popup": self.session.openWithCallback(self.hidePipOnExitCallback, MessageBox, _("Disable Picture in Picture"), simple=True) else: self.hidePipOnExitCallback(True) else: self.hide() if hasattr(self, "pvrStateDialog"): self.pvrStateDialog.hide() def hidePipOnExitCallback(self, answer): if answer: self.showPiP() def connectShowHideNotifier(self, fnc): if not fnc in self.onShowHideNotifiers: self.onShowHideNotifiers.append(fnc) def disconnectShowHideNotifier(self, fnc): if fnc in self.onShowHideNotifiers: self.onShowHideNotifiers.remove(fnc) def serviceStarted(self): if self.execing: if config.usage.show_infobar_on_zap.value: self.doShow() self.showHideVBI() def startHideTimer(self): if self.__state == self.STATE_SHOWN and not self.__locked: self.hideTimer.stop() val = int(config.usage.infobar_timeout.value) if val: self.hideTimer.start(val * 1000, True) elif (self.secondInfoBarScreen and self.secondInfoBarScreen.shown) or ((not config.usage.show_second_infobar.value or isMoviePlayerInfoBar(self)) and self.EventViewIsShown): self.hideTimer.stop() # some settings are non integer val = config.usage.show_second_infobar.value val = val.isdigit() and int(val) or 0 if val > 0: self.hideTimer.start(val * 1000, True) elif hasattr(self, "pvrStateDialog"): self.hideTimer.stop() val = int(config.usage.infobar_timeout.value) if val: self.hideTimer.start(val * 1000, True) def doShow(self): self.show() self.startHideTimer() def doTimerHide(self): self.hideTimer.stop() self.DimmingTimer = eTimer() self.DimmingTimer.callback.append(self.doDimming) self.DimmingTimer.start(70, True) self.dimmed = config.usage.show_infobar_dimming_speed.value def doHide(self): if self.__state != self.STATE_HIDDEN: if self.dimmed > 0: self.doWriteAlpha((config.av.osd_alpha.value * self.dimmed / config.usage.show_infobar_dimming_speed.value)) self.DimmingTimer.start(5, True) else: self.DimmingTimer.stop() self.hide() elif self.__state == self.STATE_HIDDEN and self.secondInfoBarScreen and self.secondInfoBarScreen.shown: if self.dimmed > 0: self.doWriteAlpha((config.av.osd_alpha.value * self.dimmed / config.usage.show_infobar_dimming_speed.value)) self.DimmingTimer.start(5, True) else: self.DimmingTimer.stop() self.secondInfoBarScreen.hide() self.secondInfoBarWasShown = False self.resetAlpha() elif self.__state == self.STATE_HIDDEN and self.EventViewIsShown: try: self.eventView.close() except: pass self.EventViewIsShown = False # elif hasattr(self, "pvrStateDialog"): # if self.dimmed > 0: # self.doWriteAlpha((config.av.osd_alpha.value*self.dimmed/config.usage.show_infobar_dimming_speed.value)) # self.DimmingTimer.start(5, True) # else: # self.DimmingTimer.stop() # try: # self.pvrStateDialog.hide() # except: # pass def toggleShow(self): if self.__state == self.STATE_HIDDEN: if not self.secondInfoBarWasShown: self.show() if self.secondInfoBarScreen: self.secondInfoBarScreen.hide() self.secondInfoBarWasShown = False self.EventViewIsShown = False elif isStandardInfoBar(self) and config.usage.show_second_infobar.value == "EPG": self.showDefaultEPG() elif isStandardInfoBar(self) and config.usage.show_second_infobar.value == "INFOBAREPG": self.openInfoBarEPG() elif self.secondInfoBarScreen and config.usage.show_second_infobar.value != "none" and not self.secondInfoBarScreen.shown: self.hide() self.secondInfoBarScreen.show() self.secondInfoBarWasShown = True self.startHideTimer() elif isMoviePlayerInfoBar(self) and not self.EventViewIsShown and config.usage.show_second_infobar.value: self.hide() try: self.openEventView(True) except: pass self.EventViewIsShown = True self.startHideTimer() else: self.hide() if self.secondInfoBarScreen and self.secondInfoBarScreen.shown: self.secondInfoBarScreen.hide() elif self.EventViewIsShown: try: self.eventView.close() except: pass self.EventViewIsShown = False def _helpToggleShowLong(self): return isinstance(self, InfoBarEPG) and config.vixsettings.InfoBarEpg_mode.value == "1" and _("Open infobar EPG...") or None def toggleShowLong(self): if isinstance(self, InfoBarEPG): if config.vixsettings.InfoBarEpg_mode.value == "1": self.openInfoBarEPG() def lockShow(self): self.__locked += 1 if self.execing: self.show() self.hideTimer.stop() def unlockShow(self): if config.usage.show_infobar_do_dimming.value and self.lastResetAlpha is False: self.doWriteAlpha(config.av.osd_alpha.value) try: self.__locked -= 1 except: self.__locked = 0 if self.__locked < 0: self.__locked = 0 if self.execing: self.startHideTimer() def checkHideVBI(self, service=None): service = service or self.session.nav.getCurrentlyPlayingServiceReference() servicepath = service and service.getPath() if servicepath: if servicepath.startswith("/"): if service.toString().startswith("1:"): info = eServiceCenter.getInstance().info(service) service = info and info.getInfoString(service, iServiceInformation.sServiceref) service = service and eServiceReference(service) if service: print service, service and service.toString() return service and ":".join(service.toString().split(":")[:11]) in whitelist_vbi else: return ".hidevbi." in servicepath.lower() return service and service.toString() in whitelist_vbi def showHideVBI(self): if self.checkHideVBI(): self.hideVBILineScreen.show() else: self.hideVBILineScreen.hide() def ToggleHideVBI(self, service=None): service = service or self.session.nav.getCurrentlyPlayingServiceReference() if service: service = service.toString() global whitelist_vbi if service in whitelist_vbi: whitelist_vbi.remove(service) else: whitelist_vbi.append(service) open('/etc/enigma2/whitelist_vbi', 'w').write('\n'.join(whitelist_vbi)) self.showHideVBI() class BufferIndicator(Screen): def __init__(self, session): Screen.__init__(self, session) self["status"] = Label() self.mayShow = False self.mayShowTimer = eTimer() self.mayShowTimer.callback.append(self.mayShowEndTimer) self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evBuffering: self.bufferChanged, iPlayableService.evStart: self.__evStart, iPlayableService.evGstreamerPlayStarted: self.__evGstreamerPlayStarted, }) def bufferChanged(self): if self.mayShow: value = self.getBufferValue() if value and value != 100: self["status"].setText(_("Buffering %d%%") % value) if not self.shown: self.show() def __evStart(self): self.hide() self.mayShow = False self.mayShowTimer.start(1000, True) def __evGstreamerPlayStarted(self): self.mayShow = False self.mayShowTimer.stop() self.hide() def mayShowEndTimer(self): self.mayShow = True if self.getBufferValue() == 0: self["status"].setText(_("No data received yet")) self.show() def getBufferValue(self): service = self.session.nav.getCurrentService() info = service and service.info() return info and info.getInfo(iServiceInformation.sBuffer) class InfoBarBuffer(): def __init__(self): self.bufferScreen = self.session.instantiateDialog(BufferIndicator) self.bufferScreen.hide() self.onClose.append(self.__onClose) def __onClose(self): if self.bufferScreen: self.bufferScreen.doClose() self.bufferScreen = None class NumberZap(Screen): def quit(self): self.Timer.stop() self.close() def keyOK(self): self.Timer.stop() self.close(self.service, self.bouquet) def handleServiceName(self): if self.searchNumber: self.service, self.bouquet = self.searchNumber(int(self["number"].getText())) self["servicename"].setText(ServiceReference(self.service).getServiceName()) self["servicename_summary"].setText(ServiceReference(self.service).getServiceName()) self["Service"].newService(self.service) if not self.startBouquet: self.startBouquet = self.bouquet def keyBlue(self): if config.misc.zapkey_delay.value > 0: self.Timer.start(1000 * config.misc.zapkey_delay.value, True) if self.searchNumber: if self.startBouquet == self.bouquet: self.service, self.bouquet = self.searchNumber(int(self["number"].getText()), firstBouquetOnly=True) else: self.service, self.bouquet = self.searchNumber(int(self["number"].getText())) self["servicename"].setText(ServiceReference(self.service).getServiceName()) self["servicename_summary"].setText(ServiceReference(self.service).getServiceName()) self["Service"].newService(self.service) def keyNumberGlobal(self, number): if config.misc.zapkey_delay.value > 0: self.Timer.start(1000 * config.misc.zapkey_delay.value, True) self.numberString += str(number) self["number"].setText(self.numberString) self["number_summary"].setText(self.numberString) self.handleServiceName() if len(self.numberString) >= int(config.usage.maxchannelnumlen.value): self.keyOK() def __init__(self, session, number, searchNumberFunction=None): Screen.__init__(self, session) self.onChangedEntry = [] self.numberString = str(number) self.searchNumber = searchNumberFunction self.startBouquet = None self["channel"] = Label(_("Channel:")) self["channel_summary"] = StaticText(_("Channel:")) self["number"] = Label(self.numberString) self["number_summary"] = StaticText(self.numberString) self["servicename"] = Label() self["servicename_summary"] = StaticText() self["Service"] = ServiceEvent() self.onLayoutFinish.append(self.handleServiceName) if config.misc.numzap_picon.value: self.skinName = ["NumberZapPicon", "NumberZap"] self["actions"] = NumberActionMap(["SetupActions", "ShortcutActions"], { "cancel": self.quit, "ok": self.keyOK, "blue": self.keyBlue, "1": self.keyNumberGlobal, "2": self.keyNumberGlobal, "3": self.keyNumberGlobal, "4": self.keyNumberGlobal, "5": self.keyNumberGlobal, "6": self.keyNumberGlobal, "7": self.keyNumberGlobal, "8": self.keyNumberGlobal, "9": self.keyNumberGlobal, "0": self.keyNumberGlobal }) self.Timer = eTimer() self.Timer.callback.append(self.keyOK) if config.misc.zapkey_delay.value > 0: self.Timer.start(1000 * config.misc.zapkey_delay.value, True) class InfoBarNumberZap: """ Handles an initial number for NumberZapping """ def __init__(self): self["NumberActions"] = HelpableNumberActionMap(self, ["NumberActions"], { "1": (self.keyNumberGlobal, _("Zap to channel number")), "2": (self.keyNumberGlobal, _("Zap to channel number")), "3": (self.keyNumberGlobal, _("Zap to channel number")), "4": (self.keyNumberGlobal, _("Zap to channel number")), "5": (self.keyNumberGlobal, _("Zap to channel number")), "6": (self.keyNumberGlobal, _("Zap to channel number")), "7": (self.keyNumberGlobal, _("Zap to channel number")), "8": (self.keyNumberGlobal, _("Zap to channel number")), "9": (self.keyNumberGlobal, _("Zap to channel number")), "0": (self.keyNumberGlobal, self._helpKeyNumberGlobal0), }, description=_("Recall channel, panic button & number zap")) def _helpKeyNumberGlobal0(self): if isinstance(self, InfoBarPiP) and self.pipHandles0Action(): return config.usage.pip_zero_button.choices[config.usage.pip_zero_button.value] elif len(self.servicelist.history) > 1: return config.usage.panicbutton.value and _("Zap to first channel & clear zap history") or _("Switch between last two channels watched") def keyNumberGlobal(self, number): if "PTSSeekPointer" in self.pvrStateDialog and self.timeshiftEnabled() and self.isSeekable(): # noinspection PyProtectedMember InfoBarTimeshiftState._mayShow(self) self.pvrStateDialog["PTSSeekPointer"].setPosition((self.pvrStateDialog["PTSSeekBack"].instance.size().width() - 4) / 2, self.pvrStateDialog["PTSSeekPointer"].position[1]) if self.seekstate != self.SEEK_STATE_PLAY: self.setSeekState(self.SEEK_STATE_PLAY) self.ptsSeekPointerOK() return if self.pts_blockZap_timer.isActive(): return # if self.save_current_timeshift and self.timeshiftEnabled(): # InfoBarTimeshift.saveTimeshiftActions(self) # return if number == 0: if isinstance(self, InfoBarPiP) and self.pipHandles0Action(): self.pipDoHandle0Action() elif len(self.servicelist.history) > 1: self.checkTimeshiftRunning(self.recallPrevService) else: if "TimeshiftActions" in self and self.timeshiftEnabled(): ts = self.getTimeshift() if ts and ts.isTimeshiftActive(): return self.session.openWithCallback(self.numberEntered, NumberZap, number, self.searchNumber) def recallPrevService(self, reply): if reply: if config.usage.panicbutton.value: if self.session.pipshown: del self.session.pip self.session.pipshown = False self.servicelist.history_tv = [] self.servicelist.history_radio = [] self.servicelist.history = self.servicelist.history_tv self.servicelist.history_pos = 0 self.servicelist2.history_tv = [] self.servicelist2.history_radio = [] self.servicelist2.history = self.servicelist.history_tv self.servicelist2.history_pos = 0 if config.usage.multibouquet.value: bqrootstr = '1:7:1:0:0:0:0:0:0:0:FROM BOUQUET "bouquets.tv" ORDER BY bouquet' else: bqrootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet' % service_types_tv serviceHandler = eServiceCenter.getInstance() rootbouquet = eServiceReference(bqrootstr) bouquet = eServiceReference(bqrootstr) bouquetlist = serviceHandler.list(bouquet) service = None if not bouquetlist is None: while True: bouquet = bouquetlist.getNext() if not bouquet.valid(): break if bouquet.flags & eServiceReference.isDirectory: self.servicelist.clearPath() self.servicelist.setRoot(bouquet) servicelist = serviceHandler.list(bouquet) if not servicelist is None: serviceIterator = servicelist.getNext() while serviceIterator.valid(): service, bouquet2 = self.searchNumber(1) if service == serviceIterator: break serviceIterator = servicelist.getNext() if serviceIterator.valid() and service == serviceIterator: break self.servicelist.enterPath(rootbouquet) self.servicelist.enterPath(bouquet) self.servicelist.saveRoot() self.servicelist2.enterPath(rootbouquet) self.servicelist2.enterPath(bouquet) self.servicelist2.saveRoot() if service is not None: self.selectAndStartService(service, bouquet) else: self.servicelist.recallPrevService() def numberEntered(self, service=None, bouquet=None): if service: self.selectAndStartService(service, bouquet) def searchNumberHelper(self, serviceHandler, num, bouquet): servicelist = serviceHandler.list(bouquet) if servicelist: serviceIterator = servicelist.getNext() while serviceIterator.valid(): if num == serviceIterator.getChannelNum(): return serviceIterator serviceIterator = servicelist.getNext() return None def searchNumber(self, number, firstBouquetOnly=False, bouquet=None): bouquet = bouquet or self.servicelist.getRoot() service = None serviceHandler = eServiceCenter.getInstance() if not firstBouquetOnly: service = self.searchNumberHelper(serviceHandler, number, bouquet) if config.usage.multibouquet.value and not service: bouquet = self.servicelist.bouquet_root bouquetlist = serviceHandler.list(bouquet) if bouquetlist: bouquet = bouquetlist.getNext() while bouquet.valid(): if bouquet.flags & eServiceReference.isDirectory and not bouquet.flags & eServiceReference.isInvisible: service = self.searchNumberHelper(serviceHandler, number, bouquet) if service: playable = not (service.flags & (eServiceReference.isMarker | eServiceReference.isDirectory)) or (service.flags & eServiceReference.isNumberedMarker) if not playable: service = None break if config.usage.alternative_number_mode.value or firstBouquetOnly: break bouquet = bouquetlist.getNext() return service, bouquet def selectAndStartService(self, service, bouquet): if service: if self.servicelist.getRoot() != bouquet: #already in correct bouquet? self.servicelist.clearPath() if self.servicelist.bouquet_root != bouquet: self.servicelist.enterPath(self.servicelist.bouquet_root) self.servicelist.enterPath(bouquet) self.servicelist.setCurrentSelection(service) #select the service in servicelist self.servicelist.zap(enable_pipzap=True) self.servicelist.correctChannelNumber() self.servicelist.startRoot = None def zapToNumber(self, number): service, bouquet = self.searchNumber(number) self.selectAndStartService(service, bouquet) config.misc.initialchannelselection = ConfigBoolean(default=True) class InfoBarChannelSelection: """ ChannelSelection - handles the channelSelection dialog and the initial channelChange actions which open the channelSelection dialog """ def __init__(self): #instantiate forever self.servicelist = self.session.instantiateDialog(ChannelSelection) self.servicelist2 = self.session.instantiateDialog(PiPZapSelection) self.tscallback = None self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection", { "switchChannelUp": (self.switchChannelUp, _("Open service list and select the previous channel")), "switchChannelDown": (self.switchChannelDown, _("Open service list and select the next channel")), "switchChannelUpLong": (self.switchChannelUpLong, _("Open service list and select the previous channel for PiP")), "switchChannelDownLong": (self.switchChannelDownLong, _("Open service list and select the next channel for PiP")), "zapUp": (self.zapUp, _("Switch to the previous channel")), "zapDown": (self.zapDown, _("Switch to the next channel")), "historyBack": (self.historyBack, _("Switch to the previous channel in history")), "historyNext": (self.historyNext, _("Switch to the next channel in history")), "openServiceList": (self.openServiceList, _("Open the service list")), "openSatellites": (self.openSatellites, _("Open the satellites list")), "openBouquets": (self.openBouquets, _("Open the favourites list")), "LeftPressed": (self.LeftPressed, self._helpLeftPressed), "RightPressed": (self.RightPressed, self._helpRightPressed), "ChannelPlusPressed": (self.zapDown, _("Switch to the next channel")), "ChannelMinusPressed": (self.zapUp, _("Switch to the previous channel")), "ChannelPlusPressedLong": (self.zapDownPip, _("Switch the PiP to the next channel")), "ChannelMinusPressedLong": (self.zapUpPip, _("Switch the PiP to the previous channel")), }, description=_("Channel selection")) self.onClose.append(self.__onClose) def __onClose(self): if self.servicelist: self.servicelist.doClose() self.servicelist = None if self.servicelist2: self.servicelist2.doClose() self.servicelist2 = None def _helpLeftRightPressed(self, zapHelp): return config.vixsettings.InfoBarEpg_mode.value == "3" and config.usage.show_second_infobar.value != "INFOBAREPG" and _("Open infobar EPG") or zapHelp def _helpLeftPressed(self): return self._helpLeftRightPressed(_("Switch to the previous channel")) def LeftPressed(self): if config.vixsettings.InfoBarEpg_mode.value == "3" and config.usage.show_second_infobar.value != "INFOBAREPG": self.openInfoBarEPG() else: self.zapUp() def _helpRightPressed(self): return self._helpLeftRightPressed(_("Switch to the next channel")) def RightPressed(self): if config.vixsettings.InfoBarEpg_mode.value == "3" and config.usage.show_second_infobar.value != "INFOBAREPG": self.openInfoBarEPG() else: self.zapDown() def showTvChannelList(self, zap=False): self.servicelist.setModeTv() if zap: self.servicelist.zap() if config.usage.show_servicelist.value: self.session.execDialog(self.servicelist) def showRadioChannelList(self, zap=False): self.servicelist.setModeRadio() if zap: self.servicelist.zap() if config.usage.show_servicelist.value: self.session.execDialog(self.servicelist) def historyBack(self): if config.usage.historymode.value == "0": self.servicelist.historyBack() else: self.servicelist.historyZap(-1) def historyNext(self): if config.usage.historymode.value == "0": self.servicelist.historyNext() else: self.servicelist.historyZap(+1) def switchChannelUp(self, servicelist=None): if not self.secondInfoBarScreen.shown: servicelist = servicelist or self.servicelist self.keyHide() if not config.usage.show_bouquetalways.value: if "keep" not in config.usage.servicelist_cursor_behavior.value: servicelist.moveUp() else: servicelist.showFavourites() self.session.execDialog(servicelist) def switchChannelUpLong(self): self.switchChannelUp(self.servicelist2 if SystemInfo.get("NumVideoDecoders", 1) > 1 else None) def switchChannelDown(self, servicelist=None): if not self.secondInfoBarScreen.shown: servicelist = servicelist or self.servicelist self.keyHide() if not config.usage.show_bouquetalways.value: if "keep" not in config.usage.servicelist_cursor_behavior.value: servicelist.moveDown() else: servicelist.showFavourites() self.session.execDialog(servicelist) def switchChannelDownLong(self): self.switchChannelDown(self.servicelist2 if SystemInfo.get("NumVideoDecoders", 1) > 1 else None) def openServiceList(self): self.session.execDialog(self.servicelist) def openServiceListPiP(self): self.session.execDialog(self.servicelist2) def openSatellites(self): self.servicelist.showSatellites() self.session.execDialog(self.servicelist) def openBouquets(self): self.servicelist.showFavourites() self.session.execDialog(self.servicelist) def zapUp(self): if self.pts_blockZap_timer.isActive(): return self.__zapUp(self.servicelist) def zapUpPip(self): if SystemInfo.get("NumVideoDecoders", 1) <= 1: self.zapUp() return if not hasattr(self.session, 'pip') and not self.session.pipshown: self.session.open(MessageBox, _("Please open Picture in Picture first"), MessageBox.TYPE_ERROR, simple=True) return self.servicelist2.dopipzap = True self.__zapUp(self.servicelist2) self.servicelist2.dopipzap = False def __zapUp(self, servicelist): if servicelist.inBouquet(): prev = servicelist.getCurrentSelection() if prev: prev = prev.toString() while True: if config.usage.quickzap_bouquet_change.value and servicelist.atBegin(): servicelist.prevBouquet() else: servicelist.moveUp() cur = servicelist.getCurrentSelection() if cur: if servicelist.dopipzap: isPlayable = self.session.pip.isPlayableForPipService(cur) else: isPlayable = isPlayableForCur(cur) if cur.toString() == prev or isPlayable: break else: servicelist.moveUp() servicelist.zap(enable_pipzap=True) def openFavouritesList(self): self.servicelist.showFavourites() self.openServiceList() def zapDown(self): if self.pts_blockZap_timer.isActive(): return self.__zapDown(self.servicelist) def zapDownPip(self): if SystemInfo.get("NumVideoDecoders", 1) <= 1: self.zapDown() return if not hasattr(self.session, 'pip') and not self.session.pipshown: self.session.open(MessageBox, _("Please open Picture in Picture first"), MessageBox.TYPE_ERROR, simple=True) return self.servicelist2.dopipzap = True self.__zapDown(self.servicelist2) self.servicelist2.dopipzap = False def __zapDown(self, servicelist): if servicelist.inBouquet(): prev = servicelist.getCurrentSelection() if prev: prev = prev.toString() while True: if config.usage.quickzap_bouquet_change.value and servicelist.atEnd(): servicelist.nextBouquet() else: servicelist.moveDown() cur = servicelist.getCurrentSelection() if cur: if servicelist.dopipzap: isPlayable = self.session.pip.isPlayableForPipService(cur) else: isPlayable = isPlayableForCur(cur) if cur.toString() == prev or isPlayable: break else: servicelist.moveDown() servicelist.zap(enable_pipzap=True) class InfoBarMenu: """ Handles a menu action, to open the (main) menu """ def __init__(self): self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", { "mainMenu": (self.mainMenu, _("Enter main menu...")), "showNetworkSetup": (self.showNetworkMounts, _("Show network mounts ...")), "showSystemSetup": (self.showSystemMenu, _("Show network mounts ...")), "showRFmod": (self.showRFSetup, _("Show RFmod setup...")), "toggleAspectRatio": (self.toggleAspectRatio, _("Toggle aspect ratio...")), }, description=_("Menu")) self.session.infobar = None def mainMenu(self): # print "loading mainmenu XML..." menu = mdom.getroot() assert menu.tag == "menu", "root element in menu must be 'menu'!" self.session.infobar = self # so we can access the currently active infobar from screens opened from within the mainmenu # at the moment used from the SubserviceSelection self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu) def mainMenuClosed(self, *val): self.session.infobar = None def toggleAspectRatio(self): ASPECT = ["auto", "16_9", "4_3"] ASPECT_MSG = {"auto": "Auto", "16_9": "16:9", "4_3": "4:3"} if config.av.aspect.value in ASPECT: index = ASPECT.index(config.av.aspect.value) config.av.aspect.value = ASPECT[(index + 1) % 3] else: config.av.aspect.value = "auto" config.av.aspect.save() self.session.open(MessageBox, _("AV aspect is %s." % ASPECT_MSG[config.av.aspect.value]), MessageBox.TYPE_INFO, timeout=5, simple=True) def showSystemMenu(self): menulist = mdom.getroot().findall('menu') for item in menulist: if item.attrib['entryID'] == 'setup_selection': menulist = item.findall('menu') for item in menulist: if item.attrib['entryID'] == 'system_selection': menu = item assert menu.tag == "menu", "root element in menu must be 'menu'!" self.session.openWithCallback(self.mainMenuClosed, Menu, menu) def showNetworkMounts(self): menulist = mdom.getroot().findall('menu') for item in menulist: if item.attrib['entryID'] == 'setup_selection': menulist = item.findall('menu') for item in menulist: if item.attrib['entryID'] == 'network_menu': menu = item assert menu.tag == "menu", "root element in menu must be 'menu'!" self.session.openWithCallback(self.mainMenuClosed, Menu, menu) def showRFSetup(self): self.session.openWithCallback(self.mainMenuClosed, Setup, 'RFmod') class InfoBarSimpleEventView: def __init__(self): pass class SimpleServicelist: def __init__(self, services): self.services = services self.length = len(services) self.current = 0 def selectService(self, service): if not self.length: self.current = -1 return False else: self.current = 0 while self.services[self.current].ref != service: self.current += 1 if self.current >= self.length: return False return True def nextService(self): if not self.length: return if self.current + 1 < self.length: self.current += 1 else: self.current = 0 def prevService(self): if not self.length: return if self.current - 1 > -1: self.current -= 1 else: self.current = self.length - 1 def currentService(self): if not self.length or self.current >= self.length: return None return self.services[self.current] class InfoBarEPG: """ EPG - Opens an EPG list when the showEPGList action fires """ def __init__(self): self.is_now_next = False self.eventView = None self.epglist = [] self.defaultEPGType = self.getDefaultEPGtype() self.defaultINFOType = self.getDefaultINFOtype() self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged, }) # Note regarding INFO button on the RCU. Some RCUs do not have an INFO button, but to make matters # more complicated they have an EPG button that sends KEY_INFO instead of KEY_EPG. To deal with # this the INFO button methods check SystemInfo["mapKeyInfoToEpgFunctions"] to see if the RCU has an INFO button # and if not the event is rerouted to the corresponding EPG button method of the same name. self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", { "RedPressed": (self.RedPressed, self._helpRedPressed), "InfoPressed": (self.showDefaultINFO, self._helpShowDefaultINFO), # SHORT INFO "showEventInfoPlugin": (self.showEventInfoPlugins, self._helpShowEventInfoPlugins), # LONG INFO "EPGPressed": (self.showDefaultEPG, self._helpShowDefaultEPG), # SHORT EPG "showSingleEPG": (self.openSingleServiceEPG, _("Show single channel EPG...")), # not in the keymap "showEventGuidePlugin": (self.showEventGuidePlugins, self._helpShowEventGuidePlugins), # LONG EPG "showInfobarOrEpgWhenInfobarAlreadyVisible": (self.showEventInfoWhenNotVisible, self._helpShowEventInfoWhenNotVisible) # not in the keymap }, description=_("EPG access")) def getEPGPluginList(self): pluginlist = [(p.name, p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EVENTINFO)] pluginlist.append(("Event Info", _("Event Info"), self.openEventView)) pluginlist.append(("Grid EPG", _("Grid EPG"), self.openGridEPG)) pluginlist.append(("Infobar EPG", _("Infobar EPG"), self.openInfoBarEPG)) pluginlist.append(("Multi EPG", _("Multi EPG"), self.openMultiServiceEPG)) pluginlist.append(("Single EPG", _("Single EPG"), self.openSingleServiceEPG)) return pluginlist def getDefaultEPGtype(self): pluginlist = self.getEPGPluginList() default = "Grid EPG" choices = [(p[0], p[1]) for p in pluginlist] if not hasattr(config.usage, "defaultEPGType"): # first run config.usage.defaultEPGType = ConfigSelection(default=default, choices=choices) config.usage.defaultEPGType.addNotifier(self.defaultEPGtypeNotifier, initial_call=False, immediate_feedback=False) for plugin in pluginlist: if plugin[0] == config.usage.defaultEPGType.value: return plugin[2] return None def getDefaultINFOtype(self): pluginlist = self.getEPGPluginList() default = "Event Info" choices = [(p[0], p[1]) for p in pluginlist] if not hasattr(config.usage, "defaultINFOType"): # first run config.usage.defaultINFOType = ConfigSelection(default=default, choices=choices) config.usage.defaultINFOType.addNotifier(self.defaultINFOtypeNotifier, initial_call=False, immediate_feedback=False) for plugin in pluginlist: if plugin[0] == config.usage.defaultINFOType.value: return plugin[2] return None def defaultEPGtypeNotifier(self, configElement): self.defaultEPGType = self.getDefaultEPGtype() def defaultINFOtypeNotifier(self, configElement): self.defaultINFOType = self.getDefaultINFOtype() def selectDefaultEpgPlugin(self): plugins = [(p[0], p[1]) for p in self.getEPGPluginList()] value = config.usage.defaultEPGType.value selection = [i for i, p in enumerate(plugins) if p[0] == value] self.session.openWithCallback(self.defaultEpgPluginChosen, ChoiceBox, title=_("Please select the default action of the EPG button"), list=plugins, skin_name="EPGExtensionsList", selection=selection and selection[0] or 0) def selectDefaultInfoPlugin(self): plugins = [(p[0], p[1]) for p in self.getEPGPluginList()] value = config.usage.defaultINFOType.value selection = [i for i, c in enumerate(plugins) if c[0] == value] self.session.openWithCallback(self.defaultInfoPluginChosen, ChoiceBox, title=_("Please select the default action of the INFO button"), list=plugins, skin_name="EPGExtensionsList", selection=selection and selection[0] or 0) def defaultEpgPluginChosen(self, answer): if answer is not None: config.usage.defaultEPGType.value = answer[0] config.usage.defaultEPGType.save() # saving also forces self.defaultEPGTypeNotifier() to update self.defaultEPGType configfile.save() def defaultInfoPluginChosen(self, answer): if answer is not None: config.usage.defaultINFOType.value = answer[0] config.usage.defaultINFOType.save() # saving also forces self.defaultINFOTypeNotifier() to update self.defaultINFOType configfile.save() def _helpShowEventGuidePlugins(self): if isMoviePlayerInfoBar(self): return _("Show program information...") else: return _("List EPG functions...") def showEventGuidePlugins(self): if isMoviePlayerInfoBar(self): self.openEventView() else: plugins = [(p[0], p[2]) for p in self.getEPGPluginList()] plugins.append((_("Select default action of EPG button"), self.selectDefaultEpgPlugin)) self.session.open(ChoiceBox, title=_("Please choose an extension..."), callbackList=plugins, skin_name="EPGExtensionsList", reorderConfig="eventinfo_order") def _helpShowEventInfoPlugins(self): if SystemInfo["mapKeyInfoToEpgFunctions"]: return self._helpShowEventGuidePlugins() if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): return _("Select default action of INFO button") def showEventInfoPlugins(self): if SystemInfo["mapKeyInfoToEpgFunctions"]: self.showEventGuidePlugins() return self.selectDefaultInfoPlugin() def runPlugin(self, plugin): plugin(session=self.session, servicelist=self.servicelist) def _helpRedPressed(self): if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): if config.usage.defaultEPGType.value != "Grid EPG": return _("Show Grid EPG") else: return _("Show single channel EPG...") return None def RedPressed(self): if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): if config.usage.defaultEPGType.value != "Grid EPG": self.openGridEPG() else: self.openSingleServiceEPG() def _helpInfoPressed(self): if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): return _("Show program information...") def InfoPressed(self): if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): self.openEventView() def _helpEPGPressed(self): if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): return _("Show Grid EPG") return None def EPGPressed(self): # This is the fallback if no defaultEPGType is available if isStandardInfoBar(self) or isMoviePlayerInfoBar(self): self.openGridEPG() def showEventInfoWhenNotVisible(self): if self.shown: self.openEventView() else: self.toggleShow() def _helpShowEventInfoWhenNotVisible(self): if self.shown: return _("Show program information...") else: return _("Toggle infobar") def zapToService(self, service, bouquet=None, preview=False, zapback=False): if self.servicelist.startServiceRef is None: self.servicelist.startServiceRef = self.session.nav.getCurrentlyPlayingServiceOrGroup() self.servicelist.currentServiceRef = self.session.nav.getCurrentlyPlayingServiceOrGroup() if service is not None: if self.servicelist.getRoot() != bouquet: #already in correct bouquet? self.servicelist.pathUp() self.servicelist.enterPath(bouquet) self.servicelist.setCurrentSelection(service) #select the service in servicelist if not zapback or preview: self.servicelist.zap(preview_zap=preview) if (self.servicelist.dopipzap or zapback) and not preview: self.servicelist.zapBack() if not preview: self.servicelist.startServiceRef = None self.servicelist.startRoot = None def getBouquetServices(self, bouquet): services = [] servicelist = eServiceCenter.getInstance().list(bouquet) if not servicelist is None: while True: service = servicelist.getNext() if not service.valid(): #check if end of list break if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services continue services.append(ServiceReference(service)) return services def multiServiceEPG(self, type, showBouquet): def openEPG(open, bouquet, bouquets): if open: bouquet = bouquet or self.servicelist.getRoot() startRef = self.lastservice if isMoviePlayerInfoBar(self) else self.session.nav.getCurrentlyPlayingServiceOrGroup() self.session.openWithCallback(self.epgClosed, type, self.zapToService, bouquet, startRef, bouquets) bouquets = self.servicelist.getEPGBouquetList() bouquetCount = len(bouquets) if bouquets else 0 if bouquetCount > 1 and showBouquet: # show bouquet list self.session.openWithCallback(openEPG, EpgBouquetSelector, bouquets, enableWrapAround=True) else: openEPG(True, None, bouquets) def openMultiServiceEPG(self): self.multiServiceEPG(EPGSelectionMulti, config.epgselection.multi.showbouquet.value) def openGridEPG(self): self.multiServiceEPG(EPGSelectionGrid, config.epgselection.grid.showbouquet.value) def openSingleServiceEPG(self): if self.servicelist is None: return startBouquet = self.servicelist.getRoot() startRef = self.lastservice if isMoviePlayerInfoBar(self) else self.session.nav.getCurrentlyPlayingServiceOrGroup() if startRef: bouquets = self.servicelist.getEPGBouquetList() self.session.openWithCallback(self.epgClosed, EPGSelectionSingle, self.zapToService, startBouquet, startRef, bouquets) def openInfoBarEPG(self): if self.servicelist is None: return startBouquet = self.servicelist.getRoot() startRef = self.session.nav.getCurrentlyPlayingServiceOrGroup() bouquets = self.servicelist.getEPGBouquetList() epgType = EPGSelectionInfobarSingle if config.epgselection.infobar.type_mode.value == 'single' else EPGSelectionInfobarGrid self.session.openWithCallback(self.epgClosed, epgType, self.zapToService, startBouquet, startRef, bouquets) def epgClosed(self, *args): if len(args) == 2 and args[0] == "Infobar": # execute one of the infobar actions action = getattr(self, args[1], None) if action: action() else: print "[UserDefinedButtons] Missing action method", actionName if len(args) == 6 and args[0] == "open": # open another EPG screen self.session.openWithCallback(self.epgClosed, args[1], self.zapToService, args[2], args[3], args[4], args[5]) elif len(args) == 1: if args[0] == 'reopengrid': self.openGridEPG() elif args[0] == 'reopeninfobar': self.openInfoBarEPG() def openSimilarList(self, eventId, refstr): self.session.open(EPGSelectionSimilar, refstr, eventId=eventId) def getNowNext(self): epglist = [] service = self.session.nav.getCurrentService() info = service and service.info() ptr = info and info.getEvent(0) if ptr: epglist.append(ptr) ptr = info and info.getEvent(1) if ptr: epglist.append(ptr) self.epglist = epglist def __evEventInfoChanged(self): if self.is_now_next: self.getNowNext() if self.eventView and self.epglist: self.eventView.setEvent(self.epglist[0]) def _helpShowDefaultEPG(self): if self.defaultEPGType is not None: return _("Show %s") % config.usage.defaultEPGType.description[config.usage.defaultEPGType.value] return self._helpEPGPressed() def showDefaultEPG(self): if self.defaultEPGType is not None: self.defaultEPGType() return self.EPGPressed() def _helpShowDefaultINFO(self): if SystemInfo['mapKeyInfoToEpgFunctions']: return self._helpShowDefaultEPG() if self.defaultINFOType is not None: return _("Show %s") % config.usage.defaultINFOType.description[config.usage.defaultINFOType.value] return self._helpINFOPressed() def showDefaultINFO(self): if SystemInfo['mapKeyInfoToEpgFunctions']: self.showDefaultEPG() return if self.defaultINFOType is not None: self.defaultINFOType() return self.InfoPressed() def openEventView(self, simple=False): if self.servicelist is None: return ref = self.session.nav.getCurrentlyPlayingServiceOrGroup() self.getNowNext() epglist = self.epglist if not epglist: self.is_now_next = False epg = eEPGCache.getInstance() ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1) if ptr: epglist.append(ptr) ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1) if ptr: epglist.append(ptr) else: self.is_now_next = True if epglist: def eventViewClosed(): self.eventView = None if not simple: self.eventView = self.session.openWithCallback(eventViewClosed, EventViewEPGSelect, epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList) else: self.eventView = self.session.openWithCallback(eventViewClosed, EventViewSimple, epglist[0], ServiceReference(ref)) def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying epglist = self.epglist if len(epglist) > 1: tmp = epglist[0] epglist[0] = epglist[1] epglist[1] = tmp setEvent(epglist[0]) class InfoBarRdsDecoder: """provides RDS and Rass support/display""" def __init__(self): self.rds_display = self.session.instantiateDialog(RdsInfoDisplay) self.session.instantiateSummaryDialog(self.rds_display) self.rds_display.setAnimationMode(0) self.rass_interactive = None self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evEnd: self.__serviceStopped, iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged }) self["RdsActions"] = HelpableActionMap(self, ["InfobarRdsActions"], { "startRassInteractive": (self.startRassInteractive, _("Open RDS/RASS screen...")), }, prio=-1, description=_("RDS/RASS display")) self["RdsActions"].setEnabled(False) self.onLayoutFinish.append(self.rds_display.show) self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged) self.onClose.append(self.__onClose) def __onClose(self): if self.rds_display: self.rds_display.doClose() self.rds_display = None def RassInteractivePossibilityChanged(self, state): self["RdsActions"].setEnabled(state) def RassSlidePicChanged(self): if not self.rass_interactive: service = self.session.nav.getCurrentService() decoder = service and service.rdsDecoder() if decoder: decoder.showRassSlidePicture() def __serviceStopped(self): if self.rass_interactive is not None: rass_interactive = self.rass_interactive self.rass_interactive = None rass_interactive.close() def startRassInteractive(self): self.rds_display.hide() self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive) def RassInteractiveClosed(self, *val): if self.rass_interactive is not None: self.rass_interactive = None self.RassSlidePicChanged() self.rds_display.show() class Seekbar(Screen): def __init__(self, session, fwd): Screen.__init__(self, session) self.setTitle(_("Seek")) self.session = session self.fwd = fwd self.percent = 0.0 self.length = None service = session.nav.getCurrentService() if service: self.seek = service.seek() if self.seek: self.length = self.seek.getLength() position = self.seek.getPlayPosition() if self.length and position and int(self.length[1]) > 0: if int(position[1]) > 0: self.percent = float(position[1]) * 100.0 / float(self.length[1]) else: self.close() self["cursor"] = MovingPixmap() self["PositionGauge"] = Label() self["time"] = Label() self["actions"] = ActionMap(["WizardActions", "DirectionActions"], { "back": self.exit, "ok": self.keyOK, "left": self.keyLeft, "right": self.keyRight }, prio=-1) self.cursorTimer = eTimer() self.cursorTimer.callback.append(self.updateCursor) self.cursorTimer.start(200, False) self.onLayoutFinish.append(self.__layoutFinished) def __layoutFinished(self): self.cursor_y = self["cursor"].instance.position().y() if hasattr(self["PositionGauge"].instance, "position") and self["PositionGauge"].instance.position().x() > 0: self.PositionGauge_x = self["PositionGauge"].instance.position().x() else: self.PositionGauge_x = 145 if hasattr(self["PositionGauge"].instance, "size") and self["PositionGauge"].instance.size().width() > 0: self.PositionGauge_w = self["PositionGauge"].instance.size().width() self.PositionGauge_w = float(self.PositionGauge_w) / 100.0 - 0.2 else: self.PositionGauge_w = 2.7 def updateCursor(self): if self.length: x = self.PositionGauge_x + int(self.PositionGauge_w * self.percent) self["cursor"].moveTo(x, self.cursor_y, 1) self["cursor"].startMoving() pts = int(float(self.length[1]) / 100.0 * self.percent) self["time"].setText("%d:%02d" % ((pts / 60 / 90000), ((pts / 90000) % 60))) def exit(self): self.cursorTimer.stop() self.close() def keyOK(self): if self.length: self.seek.seekTo(int(float(self.length[1]) / 100.0 * self.percent)) self.exit() def keyLeft(self): self.percent -= float(config.seek.sensibility.value) / 10.0 if self.percent < 0.0: self.percent = 0.0 def keyRight(self): self.percent += float(config.seek.sensibility.value) / 10.0 if self.percent > 100.0: self.percent = 100.0 class InfoBarSeek: """handles actions like seeking, pause""" SEEK_STATE_PLAY = (0, 0, 0, ">") SEEK_STATE_PAUSE = (1, 0, 0, "||") SEEK_STATE_EOF = (1, 0, 0, "END") def __init__(self, actionmap="InfobarSeekActions"): self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged, iPlayableService.evStart: self.__serviceStarted, iPlayableService.evEOF: self.__evEOF, iPlayableService.evSOF: self.__evSOF, }) self.fast_winding_hint_message_showed = False class InfoBarSeekActionMap(HelpableActionMap): def __init__(self, screen, *args, **kwargs): HelpableActionMap.__init__(self, screen, *args, **kwargs) self.screen = screen # Actions determined in self.action() self.screen.helpList.append((self, args[0], self.generateSkipHelp(actionmap))) def action(self, contexts, action): # print "action:", action time = self.seekTime(action) if time is not None: self.screen.doSeekRelative(time * 90000) return 1 else: return HelpableActionMap.action(self, contexts, action) @staticmethod def seekTime(action): if action[:5] == "seek:": time = int(action[5:]) return time elif action[:8] == "seekdef:": key = int(action[8:]) time = (-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value, -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value, -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value)[key - 1] return time return None @staticmethod def skipStringFn(skipFn): skip = skipFn() if skip is None: return None else: return "%s %3d %s" % (_("Skip forward ") if skip >= 0 else _("Skip back "), abs(skip), _("sec")) @staticmethod def skipString(skip): if callable(skip): return boundFunction(InfoBarSeekActionMap.skipStringFn, skip) else: return "%s %3d %s" % (_("Skip forward ") if skip >= 0 else _("Skip back "), abs(skip), _("sec")) @staticmethod def generateSkipHelp(context): skipHelp = [] for action in [act for ctx, act in getKeyBindingKeys(filterfn=lambda(key): key[0] == context and (key[1].startswith("seek:") or key[1].startswith("seekdef:")))]: if action.startswith("seekdef:"): skipTime = boundFunction(InfoBarSeekActionMap.seekTime, action) else: skipTime = InfoBarSeekActionMap.seekTime(action) if skipTime is not None: skipHelp.append((action, InfoBarSeekActionMap.skipString(skipTime))) return tuple(skipHelp) self["SeekActions"] = InfoBarSeekActionMap(self, actionmap, { "playpauseService": (self.playpauseService, _("Pause/Continue playback")), "pauseService": (self.pauseService, _("Pause playback")), "unPauseService": (self.unPauseService, _("Continue playback")), "okButton": (self.okButton, _("Continue playback")), "seekFwd": (self.seekFwd, _("Seek forward")), "seekFwdManual": (self.seekFwdManual, _("Seek forward (enter time)")), "seekBack": (self.seekBack, _("Seek backward")), "seekBackManual": (self.seekBackManual, _("Seek backward (enter time)")), "SeekbarFwd": self.seekFwdSeekbar, "SeekbarBack": self.seekBackSeekbar }, prio=-1, description=_("Skip, pause, rewind and fast forward")) # give them a little more priority to win over color buttons self["SeekActions"].setEnabled(False) self["SeekActionsPTS"] = InfoBarSeekActionMap(self, "InfobarSeekActionsPTS", { "playpauseService": (self.playpauseService, _("Pause/Continue playback")), "pauseService": (self.pauseService, _("Pause playback")), "unPauseService": (self.unPauseService, _("Continue playback")), "seekFwd": (self.seekFwd, _("Seek forward")), "seekBack": (self.seekBack, _("Seek backward")), }, prio=-1, description=_("Skip, pause, rewind and fast forward timeshift")) # give them a little more priority to win over color buttons self["SeekActionsPTS"].setEnabled(False) self.activity = 0 self.activityTimer = eTimer() self.activityTimer.callback.append(self.doActivityTimer) self.seekstate = self.SEEK_STATE_PLAY self.lastseekstate = self.SEEK_STATE_PLAY self.onPlayStateChanged = [] self.lockedBecauseOfSkipping = False self.__seekableStatusChanged() def makeStateForward(self, n): return 0, n, 0, ">> %dx" % n def makeStateBackward(self, n): return 0, -n, 0, "<< %dx" % n def makeStateSlowMotion(self, n): return 0, 0, n, "/%d" % n def isStateForward(self, state): return state[1] > 1 def isStateBackward(self, state): return state[1] < 0 def isStateSlowMotion(self, state): return state[1] == 0 and state[2] > 1 def getHigher(self, n, lst): for x in lst: if x > n: return x return False def getLower(self, n, lst): lst = lst[:] lst.reverse() for x in lst: if x < n: return x return False def showAfterSeek(self): if isinstance(self, InfoBarShowHide): self.doShow() def up(self): pass def down(self): pass def getSeek(self): service = self.session.nav.getCurrentService() if service is None: return None seek = service.seek() if seek is None or not seek.isCurrentlySeekable(): return None return seek def isSeekable(self): if self.getSeek() is None or (isStandardInfoBar(self) and not self.timeshiftEnabled()): return False return True def __seekableStatusChanged(self): if isStandardInfoBar(self) and self.timeshiftEnabled(): pass elif not self.isSeekable(): # print "not seekable, return to play" self["SeekActions"].setEnabled(False) self.setSeekState(self.SEEK_STATE_PLAY) else: # print "seekable" self["SeekActions"].setEnabled(True) self.activityTimer.start(200, False) for c in self.onPlayStateChanged: c(self.seekstate) def doActivityTimer(self): if self.isSeekable(): self.activity += 16 hdd = 1 if self.activity >= 100: self.activity = 0 else: self.activityTimer.stop() self.activity = 0 hdd = 0 if os.path.exists("/proc/stb/lcd/symbol_hdd"): file = open("/proc/stb/lcd/symbol_hdd", "w") file.write('%d' % int(hdd)) file.close() if os.path.exists("/proc/stb/lcd/symbol_hddprogress"): file = open("/proc/stb/lcd/symbol_hddprogress", "w") file.write('%d' % int(self.activity)) file.close() def __serviceStarted(self): self.fast_winding_hint_message_showed = False self.setSeekState(self.SEEK_STATE_PLAY) self.__seekableStatusChanged() def setSeekState(self, state): service = self.session.nav.getCurrentService() if service is None: return False if not self.isSeekable(): if state not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): state = self.SEEK_STATE_PLAY pauseable = service.pause() if pauseable is None: # print "[InfoBarGenerics] not pauseable." state = self.SEEK_STATE_PLAY self.seekstate = state if pauseable is not None: if self.seekstate[0] and self.seekstate[3] == '||': # print "[InfoBarGenerics] resolved to PAUSE" self.activityTimer.stop() pauseable.pause() elif self.seekstate[0] and self.seekstate[3] == 'END': # print "[InfoBarGenerics] resolved to STOP" self.activityTimer.stop() elif self.seekstate[1]: if not pauseable.setFastForward(self.seekstate[1]): pass # print "[InfoBarGenerics] resolved to FAST FORWARD" else: self.seekstate = self.SEEK_STATE_PLAY # print "[InfoBarGenerics] FAST FORWARD not possible: resolved to PLAY" elif self.seekstate[2]: if not pauseable.setSlowMotion(self.seekstate[2]): pass # print "[InfoBarGenerics] resolved to SLOW MOTION" else: self.seekstate = self.SEEK_STATE_PAUSE # print "[InfoBarGenerics] SLOW MOTION not possible: resolved to PAUSE" else: # print "[InfoBarGenerics] resolved to PLAY" self.activityTimer.start(200, False) pauseable.unpause() for c in self.onPlayStateChanged: c(self.seekstate) self.checkSkipShowHideLock() if hasattr(self, "ScreenSaverTimerStart"): self.ScreenSaverTimerStart() return True def okButton(self): if self.seekstate == self.SEEK_STATE_PLAY: return 0 elif self.seekstate == self.SEEK_STATE_PAUSE: self.pauseService() else: self.unPauseService() def playpauseService(self): if self.seekstate == self.SEEK_STATE_PLAY: self.pauseService() else: if self.seekstate == self.SEEK_STATE_PAUSE: if config.seek.on_pause.value == "play": self.unPauseService() elif config.seek.on_pause.value == "step": self.doSeekRelative(1) elif config.seek.on_pause.value == "last": self.setSeekState(self.lastseekstate) self.lastseekstate = self.SEEK_STATE_PLAY else: self.unPauseService() def pauseService(self): if self.seekstate != self.SEEK_STATE_EOF: self.lastseekstate = self.seekstate self.setSeekState(self.SEEK_STATE_PAUSE) def unPauseService(self): if self.seekstate == self.SEEK_STATE_PLAY: return 0 self.setSeekState(self.SEEK_STATE_PLAY) def doSeek(self, pts): seekable = self.getSeek() if seekable is None: return seekable.seekTo(pts) def doSeekRelative(self, pts): seekable = self.getSeek() if seekable is None: return prevstate = self.seekstate if self.seekstate == self.SEEK_STATE_EOF: if prevstate == self.SEEK_STATE_PAUSE: self.setSeekState(self.SEEK_STATE_PAUSE) else: self.setSeekState(self.SEEK_STATE_PLAY) seekable.seekRelative(pts < 0 and -1 or 1, abs(pts)) if abs(pts) > 100 and config.usage.show_infobar_on_skip.value: self.showAfterSeek() def seekFwd(self): seek = self.getSeek() if seek and not (seek.isCurrentlySeekable() & 2): if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1): self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10, simple=True) self.fast_winding_hint_message_showed = True return return 0 # trade as unhandled action if self.seekstate == self.SEEK_STATE_PLAY: self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value))) elif self.seekstate == self.SEEK_STATE_PAUSE: if len(config.seek.speeds_slowmotion.value): self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1])) else: self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value))) elif self.seekstate == self.SEEK_STATE_EOF: pass elif self.isStateForward(self.seekstate): speed = self.seekstate[1] if self.seekstate[2]: speed /= self.seekstate[2] speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1] self.setSeekState(self.makeStateForward(speed)) elif self.isStateBackward(self.seekstate): speed = -self.seekstate[1] if self.seekstate[2]: speed /= self.seekstate[2] speed = self.getLower(speed, config.seek.speeds_backward.value) if speed: self.setSeekState(self.makeStateBackward(speed)) else: self.setSeekState(self.SEEK_STATE_PLAY) elif self.isStateSlowMotion(self.seekstate): speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0] self.setSeekState(self.makeStateSlowMotion(speed)) def seekBack(self): seek = self.getSeek() if seek and not (seek.isCurrentlySeekable() & 2): if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1): self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10, simple=True) self.fast_winding_hint_message_showed = True return return 0 # trade as unhandled action seekstate = self.seekstate if seekstate == self.SEEK_STATE_PLAY: self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value))) elif seekstate == self.SEEK_STATE_EOF: self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value))) self.doSeekRelative(-6) elif seekstate == self.SEEK_STATE_PAUSE: self.doSeekRelative(-1) elif self.isStateForward(seekstate): speed = seekstate[1] if seekstate[2]: speed /= seekstate[2] speed = self.getLower(speed, config.seek.speeds_forward.value) if speed: self.setSeekState(self.makeStateForward(speed)) else: self.setSeekState(self.SEEK_STATE_PLAY) elif self.isStateBackward(seekstate): speed = -seekstate[1] if seekstate[2]: speed /= seekstate[2] speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1] self.setSeekState(self.makeStateBackward(speed)) elif self.isStateSlowMotion(seekstate): speed = self.getHigher(seekstate[2], config.seek.speeds_slowmotion.value) if speed: self.setSeekState(self.makeStateSlowMotion(speed)) else: self.setSeekState(self.SEEK_STATE_PAUSE) self.pts_lastseekspeed = self.seekstate[1] def _helpSeekManualSeekbar(self, manual=True, fwd=True): if manual: if fwd: return _("Skip forward (enter time in minutes)") else: return _("Skip back (enter time in minutes)") else: return _("Open seekbar") def seekFwdManual(self, fwd=True): if config.seek.baractivation.value == "leftright": self.session.open(Seekbar, fwd) else: self.session.openWithCallback(self.fwdSeekTo, MinuteInput) def seekBackManual(self, fwd=False): if config.seek.baractivation.value == "leftright": self.session.open(Seekbar, fwd) else: self.session.openWithCallback(self.rwdSeekTo, MinuteInput) def seekFwdSeekbar(self, fwd=True): if not config.seek.baractivation.value == "leftright": self.session.open(Seekbar, fwd) else: self.session.openWithCallback(self.rwdSeekTo, MinuteInput) def seekFwdVod(self, fwd=True): seekable = self.getSeek() if seekable is None: return else: if config.seek.baractivation.value == "leftright": self.session.open(Seekbar, fwd) else: self.session.openWithCallback(self.fwdSeekTo, MinuteInput) def seekFwdSeekbar(self, fwd=True): if not config.seek.baractivation.value == "leftright": self.session.open(Seekbar, fwd) else: self.session.openWithCallback(self.fwdSeekTo, MinuteInput) def fwdSeekTo(self, minutes): self.doSeekRelative(minutes * 60 * 90000) def seekBackSeekbar(self, fwd=False): if not config.seek.baractivation.value == "leftright": self.session.open(Seekbar, fwd) else: self.session.openWithCallback(self.rwdSeekTo, MinuteInput) def rwdSeekTo(self, minutes): # print "rwdSeekTo" self.doSeekRelative(-minutes * 60 * 90000) def checkSkipShowHideLock(self): if self.seekstate == self.SEEK_STATE_PLAY or self.seekstate == self.SEEK_STATE_EOF: self.lockedBecauseOfSkipping = False self.unlockShow() else: wantlock = self.seekstate != self.SEEK_STATE_PLAY if config.usage.show_infobar_on_skip.value: if self.lockedBecauseOfSkipping and not wantlock: self.unlockShow() self.lockedBecauseOfSkipping = False if wantlock and not self.lockedBecauseOfSkipping: self.lockShow() self.lockedBecauseOfSkipping = True def calcRemainingTime(self): seekable = self.getSeek() if seekable is not None: len = seekable.getLength() try: tmp = self.cueGetEndCutPosition() if tmp: len = (False, tmp) except: pass pos = seekable.getPlayPosition() speednom = self.seekstate[1] or 1 speedden = self.seekstate[2] or 1 if not len[0] and not pos[0]: if len[1] <= pos[1]: return 0 time = (len[1] - pos[1]) * speedden / (90 * speednom) return time return False def __evEOF(self): if self.seekstate == self.SEEK_STATE_EOF: return # if we are seeking forward, we try to end up ~1s before the end, and pause there. seekstate = self.seekstate if self.seekstate != self.SEEK_STATE_PAUSE: self.setSeekState(self.SEEK_STATE_EOF) if seekstate not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): # if we are seeking seekable = self.getSeek() if seekable is not None: seekable.seekTo(-1) self.doEofInternal(True) if seekstate == self.SEEK_STATE_PLAY: # regular EOF self.doEofInternal(True) else: self.doEofInternal(False) def doEofInternal(self, playing): pass # Defined in subclasses def __evSOF(self): self.setSeekState(self.SEEK_STATE_PLAY) self.doSeek(0) class InfoBarPVRState: def __init__(self, screen=PVRState, force_show=False): self.onChangedEntry = [] self.onPlayStateChanged.append(self.__playStateChanged) self.pvrStateDialog = self.session.instantiateDialog(screen) self.pvrStateDialog.setAnimationMode(0) self.onShow.append(self._mayShow) self.onHide.append(self.pvrStateDialog.hide) self.force_show = force_show self.onClose.append(self.__onClose) def __onClose(self): if self.pvrStateDialog: self.pvrStateDialog.doClose() self.pvrStateDialog = None def createSummary(self): return InfoBarMoviePlayerSummary def _mayShow(self): if "state" in self and not config.usage.movieplayer_pvrstate.value: self["state"].setText("") self["statusicon"].setPixmapNum(6) self["speed"].setText("") if self.shown and self.seekstate != self.SEEK_STATE_EOF and not config.usage.movieplayer_pvrstate.value: self.pvrStateDialog.show() self.startHideTimer() def __playStateChanged(self, state): playstateString = state[3] state_summary = playstateString self.pvrStateDialog["state"].setText(playstateString) if playstateString == '>': self.pvrStateDialog["statusicon"].setPixmapNum(0) self.pvrStateDialog["speed"].setText("") speed_summary = self.pvrStateDialog["speed"].text statusicon_summary = 0 if "state" in self and config.usage.movieplayer_pvrstate.value: self["state"].setText(playstateString) self["statusicon"].setPixmapNum(0) self["speed"].setText("") elif playstateString == '||': self.pvrStateDialog["statusicon"].setPixmapNum(1) self.pvrStateDialog["speed"].setText("") speed_summary = self.pvrStateDialog["speed"].text statusicon_summary = 1 if "state" in self and config.usage.movieplayer_pvrstate.value: self["state"].setText(playstateString) self["statusicon"].setPixmapNum(1) self["speed"].setText("") elif playstateString == 'END': self.pvrStateDialog["statusicon"].setPixmapNum(2) self.pvrStateDialog["speed"].setText("") speed_summary = self.pvrStateDialog["speed"].text statusicon_summary = 2 if "state" in self and config.usage.movieplayer_pvrstate.value: self["state"].setText(playstateString) self["statusicon"].setPixmapNum(2) self["speed"].setText("") elif playstateString.startswith('>>'): speed = state[3].split() self.pvrStateDialog["statusicon"].setPixmapNum(3) self.pvrStateDialog["speed"].setText(speed[1]) speed_summary = self.pvrStateDialog["speed"].text statusicon_summary = 3 if "state" in self and config.usage.movieplayer_pvrstate.value: self["state"].setText(playstateString) self["statusicon"].setPixmapNum(3) self["speed"].setText(speed[1]) elif playstateString.startswith('<<'): speed = state[3].split() self.pvrStateDialog["statusicon"].setPixmapNum(4) self.pvrStateDialog["speed"].setText(speed[1]) speed_summary = self.pvrStateDialog["speed"].text statusicon_summary = 4 if "state" in self and config.usage.movieplayer_pvrstate.value: self["state"].setText(playstateString) self["statusicon"].setPixmapNum(4) self["speed"].setText(speed[1]) elif playstateString.startswith('/'): self.pvrStateDialog["statusicon"].setPixmapNum(5) self.pvrStateDialog["speed"].setText(playstateString) speed_summary = self.pvrStateDialog["speed"].text statusicon_summary = 5 if "state" in self and config.usage.movieplayer_pvrstate.value: self["state"].setText(playstateString) self["statusicon"].setPixmapNum(5) self["speed"].setText(playstateString) for cb in self.onChangedEntry: cb(state_summary, speed_summary, statusicon_summary) # if we return into "PLAY" state, ensure that the dialog gets hidden if there will be no infobar displayed if not config.usage.show_infobar_on_skip.value and self.seekstate == self.SEEK_STATE_PLAY and not self.force_show: self.pvrStateDialog.hide() else: self._mayShow() class InfoBarTimeshiftState(InfoBarPVRState): def __init__(self): InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show=True) self.onPlayStateChanged.append(self.__timeshiftEventName) self.onHide.append(self.__hideTimeshiftState) def _mayShow(self): if self.shown and self.timeshiftEnabled() and self.isSeekable(): # noinspection PyCallByClass InfoBarTimeshift.ptsSeekPointerSetCurrentPos(self) if config.timeshift.showinfobar.value: self["TimeshiftSeekPointerActions"].setEnabled(True) self.pvrStateDialog.show() self.startHideTimer() def __hideTimeshiftState(self): self["TimeshiftSeekPointerActions"].setEnabled(False) self.pvrStateDialog.hide() def __timeshiftEventName(self, state): if os.path.exists("%spts_livebuffer_%s.meta" % (config.usage.timeshift_path.value, self.pts_currplaying)): readmetafile = open("%spts_livebuffer_%s.meta" % (config.usage.timeshift_path.value, self.pts_currplaying), "r") servicerefname = readmetafile.readline()[0:-1] eventname = readmetafile.readline()[0:-1] readmetafile.close() self.pvrStateDialog["eventname"].setText(eventname) else: self.pvrStateDialog["eventname"].setText("") class InfoBarShowMovies: # i don't really like this class. # it calls a not further specified "movie list" on up/down/movieList, # so this is not more than an action map def __init__(self): self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", { "movieList": (self.showMovies, _("Open the movie list")), "up": (self.up, _("Open the movie list")), "down": (self.down, _("Open the movie list")) }, description=_("Open the movie list")) from Screens.PiPSetup import PiPSetup class InfoBarExtensions: EXTENSION_SINGLE = 0 EXTENSION_LIST = 1 def __init__(self): self.list = [] if config.vixsettings.ColouredButtons.value: self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions", { "extensions": (self.showExtensionSelection, _("Show extensions...")), "showPluginBrowser": (self.showPluginBrowser, _("Show the plugin browser..")), "openTimerList": (self.showTimerList, _("Show the list of timers.")), "openAutoTimerList": (self.showAutoTimerList, _("Show the list of autotimers.")), "openEPGSearch": (self.showEPGSearch, _("Search the epg for the current event.")), "openIMDB": (self.showIMDB, _("Search IMDb for information about the current event.")), "openDreamPlex": (self.showDreamPlex, _("Show the DreamPlex player...")), }, prio=1, description=_("Access extensions")) # lower priority else: self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions", { "extensions": (self.showExtensionSelection, _("View extensions...")), "showPluginBrowser": (self.showPluginBrowser, _("Show the plugin browser..")), "showDreamPlex": (self.showDreamPlex, _("Show the DreamPlex player...")), }, prio=1, description=_("Access extensions")) # lower priority for p in plugins.getPlugins(PluginDescriptor.WHERE_EXTENSIONSINGLE): p(self) self.addExtension(extension=self.getLogManager, type=InfoBarExtensions.EXTENSION_LIST) self.addExtension(extension=self.getOsd3DSetup, type=InfoBarExtensions.EXTENSION_LIST) self.addExtension(extension=self.getCCcamInfo, type=InfoBarExtensions.EXTENSION_LIST) self.addExtension(extension=self.getOScamInfo, type=InfoBarExtensions.EXTENSION_LIST) def getLMname(self): return _("Log Manager") def getLogManager(self): if config.logmanager.showinextensions.value: return [((boundFunction(self.getLMname), boundFunction(self.openLogManager), lambda: True), None)] else: return [] def get3DSetupname(self): return _("OSD 3D Setup") def getOsd3DSetup(self): if config.osd.show3dextensions .value: return [((boundFunction(self.get3DSetupname), boundFunction(self.open3DSetup), lambda: True), None)] else: return [] def getCCname(self): return _("CCcam Info") def getCCcamInfo(self): softcams = [] if pathExists('/usr/softcams/'): softcams = os.listdir('/usr/softcams/') for softcam in softcams: if softcam.lower().startswith('cccam') and config.cccaminfo.showInExtensions.value: return [((boundFunction(self.getCCname), boundFunction(self.openCCcamInfo), lambda: True), None)] or [] else: return [] def getOSname(self): return _("OScam/Ncam Info") def getOScamInfo(self): softcams = [] if pathExists('/usr/softcams/'): softcams = os.listdir('/usr/softcams/') for softcam in softcams: if (softcam.lower().startswith('oscam') or softcam.lower().startswith('ncam')) and config.oscaminfo.showInExtensions.value: return [((boundFunction(self.getOSname), boundFunction(self.openOScamInfo), lambda: True), None)] or [] else: return [] def addExtension(self, extension, key=None, type=EXTENSION_SINGLE): self.list.append((type, extension, key)) def updateExtension(self, extension, key=None): self.extensionsList.append(extension) if key is not None and key in self.extensionKeys: key = None if key is None: for x in self.availableKeys: if x not in self.extensionKeys: key = x break if key is not None: self.extensionKeys[key] = len(self.extensionsList) - 1 def updateExtensions(self): self.extensionsList = [] self.availableKeys = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue"] self.extensionKeys = {} for x in self.list: if x[0] == self.EXTENSION_SINGLE: self.updateExtension(x[1], x[2]) else: for y in x[1](): self.updateExtension(y[0], y[1]) def showExtensionSelection(self): self.updateExtensions() extensionsList = self.extensionsList[:] keys = [] list = [] for x in self.availableKeys: if x in self.extensionKeys: entry = self.extensionKeys[x] extension = self.extensionsList[entry] if extension[2](): name = str(extension[0]()) list.append((extension[0](), extension)) keys.append(x) extensionsList.remove(extension) else: extensionsList.remove(extension) list.extend([(x[0](), x) for x in extensionsList]) keys += [""] * len(extensionsList) self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list=list, keys=keys, skin_name="ExtensionsList", reorderConfig="extension_order") def extensionCallback(self, answer): if answer is not None: answer[1][1]() def showPluginBrowser(self): from Screens.PluginBrowser import PluginBrowser self.session.open(PluginBrowser) def openCCcamInfo(self): from Screens.CCcamInfo import CCcamInfoMain self.session.open(CCcamInfoMain) def openOScamInfo(self): from Screens.OScamInfo import OscamInfoMenu self.session.open(OscamInfoMenu) def showTimerList(self): self.session.open(TimerEditList) def openLogManager(self): from Screens.LogManager import LogManager self.session.open(LogManager) def open3DSetup(self): from Screens.UserInterfacePositioner import OSD3DSetupScreen self.session.open(OSD3DSetupScreen) @staticmethod def _getAutoTimerPluginFunc(): # Use the WHERE_MENU descriptor because it's the only # AutoTimer plugin descriptor that opens the AotoTimer # overview and is always present. for l in plugins.getPlugins(PluginDescriptor.WHERE_MENU): if l.name == _("Auto Timers"): # Must use translated name menuEntry = l("timermenu") if menuEntry and len(menuEntry[0]) > 1 and callable(menuEntry[0][1]): return menuEntry[0][1] return None def showAutoTimerList(self): autotimerFunc = self._getAutoTimerPluginFunc() if autotimerFunc is not None: autotimerFunc(self.session) else: self.session.open(MessageBox, _("The AutoTimer plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10, simple=True) def showEPGSearch(self): try: from Plugins.Extensions.EPGSearch.EPGSearch import EPGSearch except ImportError: self.session.open(MessageBox, _("The EPGSearch plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10, simple=True) return s = self.session.nav.getCurrentService() if s: info = s.info() event = info.getEvent(0) # 0 = now, 1 = next if event: name = event and event.getEventName() or '' else: name = self.session.nav.getCurrentlyPlayingServiceOrGroup().toString() name = name.split('/') name = name[-1] name = name.replace('.', ' ') name = name.split('-') name = name[0] if name.endswith(' '): name = name[:-1] if name: self.session.open(EPGSearch, name, False) else: self.session.open(EPGSearch) else: self.session.open(EPGSearch) def showIMDB(self): try: from Plugins.Extensions.IMDb.plugin import IMDB s = self.session.nav.getCurrentService() if s: info = s.info() event = info.getEvent(0) # 0 = now, 1 = next name = event and event.getEventName() or '' self.session.open(IMDB, name) except ImportError: self.session.open(MessageBox, _("The IMDb plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10, simple=True) def showDreamPlex(self): try: from Plugins.Extensions.DreamPlex.plugin import DPS_MainMenu self.session.open(DPS_MainMenu) except ImportError: self.session.open(MessageBox, _("The DreamPlex plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10, simple=True) from Tools.BoundFunction import boundFunction import inspect # depends on InfoBarExtensions class InfoBarPlugins: def __init__(self): self.addExtension(extension=self.getPluginList, type=InfoBarExtensions.EXTENSION_LIST) def getPluginName(self, name): return name def getPluginList(self): l = [] for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EXTENSIONSMENU): args = inspect.getargspec(p.__call__)[0] if len(args) == 1 or len(args) == 2 and isinstance(self, InfoBarChannelSelection): l.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name)) l.sort(key=lambda e: e[2]) # sort by name return l def runPlugin(self, plugin): if isinstance(self, InfoBarChannelSelection): plugin(session=self.session, servicelist=self.servicelist) else: plugin(session=self.session) from Components.Task import job_manager class InfoBarJobman: def __init__(self): self.addExtension(extension=self.getJobList, type=InfoBarExtensions.EXTENSION_LIST) def getJobList(self): if config.usage.jobtaskextensions.value: return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()] else: return [] def getJobName(self, job): return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100 * job.progress / float(job.end))) def showJobView(self, job): from Screens.TaskView import JobView job_manager.in_background = False self.session.openWithCallback(self.JobViewCB, JobView, job) def JobViewCB(self, in_background): job_manager.in_background = in_background # depends on InfoBarExtensions class InfoBarPiP: def __init__(self): try: self.session.pipshown except: self.session.pipshown = False self.lastPiPService = None if SystemInfo["PIPAvailable"] and isinstance(self, InfoBarEPG): self["PiPActions"] = HelpableActionMap(self, "InfobarPiPActions", { "activatePiP": (self.activePiP, self.activePiPName), }, description=_("Picture in Picture (PIP)")) if self.allowPiP: self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue") self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green") self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow") self.addExtension((self.getTogglePipzapName, self.togglePipzap, self.pipShown), "red") else: self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue") self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green") self.lastPiPServiceTimeout = eTimer() self.lastPiPServiceTimeout.callback.append(self.clearLastPiPService) def pipShown(self): return self.session.pipshown def pipHandles0Action(self): return self.pipShown() and config.usage.pip_zero_button.value != "standard" def getShowHideName(self): if self.session.pipshown: return _("Disable Picture in Picture") else: return _("Activate Picture in Picture") def getSwapName(self): return _("Swap services") def getMoveName(self): return _("Move Picture in Picture") def getTogglePipzapName(self): slist = self.servicelist if slist and slist.dopipzap: return _("Zap focus to main screen") return _("Zap focus to Picture in Picture") def togglePipzap(self): if not self.session.pipshown: self.showPiP() slist = self.servicelist if slist and self.session.pipshown: slist.togglePipzap() if slist.dopipzap: currentServicePath = slist.getCurrentServicePath() self.servicelist.setCurrentServicePath(self.session.pip.servicePath, doZap=False) self.session.pip.servicePath = currentServicePath def showPiP(self): if self.session.pipshown: slist = self.servicelist if slist and slist.dopipzap: self.togglePipzap() if self.session.pipshown: self.lastPiPService = self.session.pip.getCurrentServiceReference() self.lastPiPServiceTimeout.startLongTimer(60) del self.session.pip if SystemInfo["LCDMiniTVPiP"] and int(config.lcd.minitvpipmode.value) >= 1: print '[LCDMiniTV] disable PIP' f = open("/proc/stb/lcd/mode", "w") f.write(config.lcd.minitvmode.value) f.close() self.session.pipshown = False if hasattr(self, "ScreenSaverTimerStart"): self.ScreenSaverTimerStart() else: service = self.session.nav.getCurrentService() info = service and service.info() if info: self.session.pip = self.session.instantiateDialog(PictureInPicture) self.session.pip.setAnimationMode(0) self.session.pip.show() newservice = self.lastPiPService or self.session.nav.getCurrentlyPlayingServiceReference() or self.servicelist.servicelist.getCurrent() if self.session.pip.playService(newservice): self.session.pipshown = True self.session.pip.servicePath = self.servicelist.getCurrentServicePath() if SystemInfo["LCDMiniTVPiP"] and int(config.lcd.minitvpipmode.value) >= 1: print '[LCDMiniTV] enable PIP' f = open("/proc/stb/lcd/mode", "w") f.write(config.lcd.minitvpipmode.value) f.close() f = open("/proc/stb/vmpeg/1/dst_width", "w") f.write("0") f.close() f = open("/proc/stb/vmpeg/1/dst_height", "w") f.write("0") f.close() f = open("/proc/stb/vmpeg/1/dst_apply", "w") f.write("1") f.close() else: newservice = self.session.nav.getCurrentlyPlayingServiceReference() or self.servicelist.servicelist.getCurrent() if self.session.pip.playService(newservice): self.session.pipshown = True self.session.pip.servicePath = self.servicelist.getCurrentServicePath() if SystemInfo["LCDMiniTVPiP"] and int(config.lcd.minitvpipmode.value) >= 1: print '[LCDMiniTV] enable PIP' f = open("/proc/stb/lcd/mode", "w") f.write(config.lcd.minitvpipmode.value) f.close() f = open("/proc/stb/vmpeg/1/dst_width", "w") f.write("0") f.close() f = open("/proc/stb/vmpeg/1/dst_height", "w") f.write("0") f.close() f = open("/proc/stb/vmpeg/1/dst_apply", "w") f.write("1") f.close() else: self.lastPiPService = None self.session.pipshown = False del self.session.pip else: self.session.open(MessageBox, _("No active channel found."), type=MessageBox.TYPE_INFO, timeout=5, simple=True) if self.session.pipshown and hasattr(self, "screenSaverTimer"): self.screenSaverTimer.stop() def clearLastPiPService(self): self.lastPiPService = None def activePiP(self): if self.servicelist and self.servicelist.dopipzap or not self.session.pipshown: self.showPiP() else: self.togglePipzap() def activePiPName(self): if self.servicelist and self.servicelist.dopipzap: return _("Disable Picture in Picture") if self.session.pipshown: return _("Zap focus to Picture in Picture") else: return _("Activate Picture in Picture") def swapPiP(self): if self.pipShown(): swapservice = self.session.nav.getCurrentlyPlayingServiceOrGroup() pipref = self.session.pip.getCurrentService() if swapservice and pipref and pipref.toString() != swapservice.toString(): currentServicePath = self.servicelist.getCurrentServicePath() currentBouquet = self.servicelist and self.servicelist.getRoot() self.servicelist.setCurrentServicePath(self.session.pip.servicePath, doZap=False) self.session.pip.playService(swapservice) self.session.nav.playService(pipref, checkParentalControl=False, adjust=False) self.session.pip.servicePath = currentServicePath self.session.pip.servicePath[1] = currentBouquet if self.servicelist.dopipzap: # This unfortunately won't work with subservices self.servicelist.setCurrentSelection(self.session.pip.getCurrentService()) def movePiP(self): if self.pipShown(): self.session.open(PiPSetup, pip=self.session.pip) def pipDoHandle0Action(self): use = config.usage.pip_zero_button.value if "swap" == use: self.swapPiP() elif "swapstop" == use: self.swapPiP() self.showPiP() elif "stop" == use: self.showPiP() class InfoBarInstantRecord: """Instant Record - handles the instantRecord action in order to start/stop instant records""" def __init__(self): self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord", { "instantRecord": (self.instantRecord, _("Instant recording...")), }, description=_("Instant recording")) self.SelectedInstantServiceRef = None if isStandardInfoBar(self): self.recording = [] else: from Screens.InfoBar import InfoBar InfoBarInstance = InfoBar.instance if InfoBarInstance: self.recording = InfoBarInstance.recording def moveToTrash(self, entry): print "[InfoBarGenerics] instantRecord stop and delete recording: ", entry.name import Tools.Trashcan trash = Tools.Trashcan.createTrashFolder(entry.Filename) from MovieSelection import moveServiceFiles # Don't crash on errors...the sub-handlers trap and re-raise errors... try: moveServiceFiles(entry.Filename, trash, entry.name, allowCopy=False) except: pass def stopCurrentRecording(self, entry=-1): def confirm(answer=False): if answer: self.session.nav.RecordTimer.removeEntry(self.recording[entry]) if self.deleteRecording: self.moveToTrash(self.recording[entry]) self.recording.remove(self.recording[entry]) if entry is not None and entry != -1: msg = _("Stop recording:") if self.deleteRecording: msg = _("Stop and delete recording:") msg += "\n" msg += " - " + self.recording[entry].name + "\n" self.session.openWithCallback(confirm, MessageBox, msg, MessageBox.TYPE_YESNO, simple=True) def stopAllCurrentRecordings(self, list): def confirm(answer=False): if answer: for entry in list: self.session.nav.RecordTimer.removeEntry(entry[0]) self.recording.remove(entry[0]) if self.deleteRecording: self.moveToTrash(entry[0]) msg = _("Stop recordings:") if self.deleteRecording: msg = _("Stop and delete recordings:") msg += "\n" for entry in list: msg += " - " + entry[0].name + "\n" self.session.openWithCallback(confirm, MessageBox, msg, MessageBox.TYPE_YESNO, simple=True) def getProgramInfoAndEvent(self, info, name): service = hasattr(self, "SelectedInstantServiceRef") and self.SelectedInstantServiceRef or self.session.nav.getCurrentlyPlayingServiceOrGroup() # try to get event info event = None try: epg = eEPGCache.getInstance() event = epg.lookupEventTime(service, -1, 0) if event is None: if hasattr(self, "SelectedInstantServiceRef") and self.SelectedInstantServiceRef: service_info = eServiceCenter.getInstance().info(self.SelectedInstantServiceRef) event = service_info and service_info.getEvent(self.SelectedInstantServiceRef) else: # note that this is not an eServiceReference object iService = self.session.nav.getCurrentService() event = iService and iService.info().getEvent(0) except: pass info["serviceref"] = service info["event"] = event info["name"] = name info["description"] = "" info["eventid"] = None if event is not None: curEvent = parseEvent(event, service=service) info["name"] = curEvent[2] info["description"] = curEvent[3] info["eventid"] = curEvent[4] info["end"] = curEvent[1] def startInstantRecording(self, limitEvent=False): begin = int(time()) end = begin + 3600 # dummy name = "instant record" info = {} self.getProgramInfoAndEvent(info, name) serviceref = info["serviceref"] event = info["event"] if event is not None: if limitEvent: end = info["end"] else: if limitEvent: self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO, simple=True) if isinstance(serviceref, eServiceReference): serviceref = ServiceReference(serviceref) recording = RecordTimerEntry(serviceref, begin, end, info["name"], info["description"], info["eventid"], dirname=preferredInstantRecordPath()) recording.dontSave = True if event is None or limitEvent == False: recording.autoincrease = True recording.setAutoincreaseEnd() simulTimerList = self.session.nav.RecordTimer.record(recording) if simulTimerList is None: # no conflict recording.autoincrease = False self.recording.append(recording) else: if len(simulTimerList) > 1: # with other recording name = simulTimerList[1].name name_date = ' '.join((name, strftime('%F %T', localtime(simulTimerList[1].begin)))) # print "[TIMER] conflicts with", name_date recording.autoincrease = True # start with max available length, then increment if recording.setAutoincreaseEnd(): self.session.nav.RecordTimer.record(recording) self.recording.append(recording) self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO, simple=True) else: self.session.open(MessageBox, _("Could not record due to a conflicting timer %s") % name, MessageBox.TYPE_INFO, simple=True) else: self.session.open(MessageBox, _("Could not record due to an invalid service %s") % serviceref, MessageBox.TYPE_INFO, simple=True) recording.autoincrease = False def isInstantRecordRunning(self): # print "self.recording:", self.recording if self.recording: for x in self.recording: if x.isRunning(): return True return False def recordQuestionCallback(self, answer): # print 'recordQuestionCallback' # print "pre:\n", self.recording # print 'test1' if answer is None or answer[1] == "no": # print 'test2' return list = [] recording = self.recording[:] for x in recording: if not x in self.session.nav.RecordTimer.timer_list: self.recording.remove(x) elif x.dontSave and x.isRunning(): list.append((x, False)) self.deleteRecording = False if answer[1] == "changeduration": if len(self.recording) == 1: self.changeDuration(0) else: self.session.openWithCallback(self.changeDuration, TimerSelection, list) elif answer[1] == "addrecordingtime": if len(self.recording) == 1: self.addRecordingTime(0) else: self.session.openWithCallback(self.addRecordingTime, TimerSelection, list) elif answer[1] == "changeendtime": if len(self.recording) == 1: self.setEndtime(0) else: self.session.openWithCallback(self.setEndtime, TimerSelection, list) elif answer[1] == "timer": import TimerEdit self.session.open(TimerEdit.TimerEditList) elif answer[1] == "stop": if len(self.recording) == 1: self.stopCurrentRecording(0) else: self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list) elif answer[1] == "stopdelete": self.deleteRecording = True if len(self.recording) == 1: self.stopCurrentRecording(0) else: self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list) elif answer[1] == "stopall": self.stopAllCurrentRecordings(list) elif answer[1] == "stopdeleteall": self.deleteRecording = True self.stopAllCurrentRecordings(list) elif answer[1] in ("indefinitely", "manualduration", "manualendtime", "event"): self.startInstantRecording(limitEvent=answer[1] in ("event", "manualendtime") or False) if answer[1] == "manualduration": self.changeDuration(len(self.recording) - 1) elif answer[1] == "manualendtime": self.setEndtime(len(self.recording) - 1) elif answer[1] == "savetimeshift": # print 'test1' if self.isSeekable() and self.pts_eventcount != self.pts_currplaying: # print 'test2' # noinspection PyCallByClass InfoBarTimeshift.SaveTimeshift(self, timeshiftfile="pts_livebuffer_%s" % self.pts_currplaying) else: # print 'test3' Notifications.AddNotification(MessageBox, _("Timeshift will get saved at the end of an event!"), MessageBox.TYPE_INFO, timeout=5) self.save_current_timeshift = True config.timeshift.isRecording.value = True elif answer[1] == "savetimeshiftEvent": # print 'test4' # noinspection PyCallByClass InfoBarTimeshift.saveTimeshiftEventPopup(self) elif answer[1].startswith("pts_livebuffer") is True: # print 'test2' # noinspection PyCallByClass InfoBarTimeshift.SaveTimeshift(self, timeshiftfile=answer[1]) def setEndtime(self, entry): if entry is not None and entry >= 0: self.selectedEntry = entry self.endtime = ConfigClock(default=self.recording[self.selectedEntry].end) dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime) dlg.setTitle(_("Please change the recording end time")) def TimeDateInputClosed(self, ret): if len(ret) > 1: if ret[0]: # print "[InfoBarGenerics] stopping recording at", strftime("%F %T", localtime(ret[1])) if self.recording[self.selectedEntry].end != ret[1]: self.recording[self.selectedEntry].autoincrease = False self.recording[self.selectedEntry].end = ret[1] else: if self.recording[self.selectedEntry].end != int(time()): self.recording[self.selectedEntry].autoincrease = False self.recording[self.selectedEntry].end = int(time()) self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry]) def changeDuration(self, entry): if entry is not None and entry >= 0: self.selectedEntry = entry self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record for?"), text="5 ", maxSize=True, type=Input.NUMBER) def addRecordingTime(self, entry): if entry is not None and entry >= 0: self.selectedEntry = entry self.session.openWithCallback(self.inputAddRecordingTime, InputBox, title=_("How many minutes do you want add to the recording?"), text="5 ", maxSize=True, type=Input.NUMBER) def inputAddRecordingTime(self, value): if value: print "[InfoBarGenerics] added", int(value), "minutes for recording." entry = self.recording[self.selectedEntry] if int(value) != 0: entry.autoincrease = False entry.end += 60 * int(value) self.session.nav.RecordTimer.timeChanged(entry) def inputCallback(self, value): entry = self.recording[self.selectedEntry] if value is not None: print "[InfoBarGenerics] stopping recording after", int(value), "minutes." if int(value) != 0: entry.autoincrease = False entry.end = int(time()) + 60 * int(value) else: if entry.end != int(time()): entry.autoincrease = False entry.end = int(time()) self.session.nav.RecordTimer.timeChanged(entry) def isTimerRecordRunning(self): identical = timers = 0 for timer in self.session.nav.RecordTimer.timer_list: if timer.isRunning() and not timer.justplay: timers += 1 if self.recording: for x in self.recording: if x.isRunning() and x == timer: identical += 1 return timers > identical def instantRecord(self, serviceRef=None): self.SelectedInstantServiceRef = serviceRef pirr = preferredInstantRecordPath() if not findSafeRecordPath(pirr) and not findSafeRecordPath(defaultMoviePath()): if not pirr: pirr = "" self.session.open(MessageBox, _("Missing ") + "\n" + pirr + "\n" + _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR, simple=True) return if isStandardInfoBar(self): common = ((_("Add recording (stop after current event)"), "event"), (_("Add recording (indefinitely)"), "indefinitely"), (_("Add recording (enter recording duration)"), "manualduration"), (_("Add recording (enter recording endtime)"), "manualendtime"),) timeshiftcommon = ((_("Timeshift save recording (stop after current event)"), "savetimeshift"), (_("Timeshift save recording (Select event)"), "savetimeshiftEvent"),) else: common = () timeshiftcommon = () if self.isInstantRecordRunning(): title = _("A recording is currently in progress.\nWhat do you want to do?") list = common + \ ((_("Change recording (duration)"), "changeduration"), (_("Change recording (add time)"), "addrecordingtime"), (_("Change recording (end time)"), "changeendtime"),) list += ((_("Stop recording"), "stop"),) if config.usage.movielist_trashcan.value: list += ((_("Stop and delete recording"), "stopdelete"),) if len(self.recording) > 1: list += ((_("Stop all current recordings"), "stopall"),) if config.usage.movielist_trashcan.value: list += ((_("Stop and delete all current recordings"), "stopdeleteall"),) if self.isTimerRecordRunning(): list += ((_("Stop timer recording"), "timer"),) else: title = _("Start recording?") list = common if self.isTimerRecordRunning(): list += ((_("Stop timer recording"), "timer"),) if isStandardInfoBar(self) and self.timeshiftEnabled(): list = list + timeshiftcommon if isStandardInfoBar(self): list = list + ((_("Do not record"), "no"),) if list: self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=title, list=list) else: return 0 class InfoBarAudioSelection: def __init__(self): self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", { "audioSelection": (self.audioSelection, _("Audio options...")), "audioSelectionLong": (self.audioSelectionLong, _("Toggle Digital downmix...")), }, description=_("Audio track selection, downmix and other audio options")) def audioSelection(self): from Screens.AudioSelection import AudioSelection self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self) def audioSelected(self, ret=None): print "[InfoBarGenerics][audioSelected] ", ret def audioSelectionLong(self): if SystemInfo["CanDownmixAC3"]: if config.av.downmix_ac3.value: message = _("Dobly Digital downmix is now") + " " + _("disabled") print '[InfoBarGenerics] [Audio] Dobly Digital downmix is now disabled' config.av.downmix_ac3.setValue(False) else: config.av.downmix_ac3.setValue(True) message = _("Dobly Digital downmix is now") + " " + _("enabled") print '[InfoBarGenerics] [Audio] Dobly Digital downmix is now enabled' Notifications.AddPopup(text=message, type=MessageBox.TYPE_INFO, timeout=5, id="DDdownmixToggle") class InfoBarSubserviceSelection: def __init__(self): self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions", { "GreenPressed": (self.GreenPressed, self._helpGreenPressed) }, description=_("Subservice selection")) self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions", { "nextSubservice": (self.nextSubservice, _("Switch to next sub service")), "prevSubservice": (self.prevSubservice, _("Switch to previous sub service")) }, prio=-10, description=_("Subservice selection")) self["SubserviceQuickzapAction"].setEnabled(False) self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail }) self.bouquets = self.bsel = self.selectedSubservice = None def _helpGreenPressed(self): if not config.vixsettings.Subservice.value: return _("Show the list of timers.") else: return _("Show subservice selection list...") def GreenPressed(self): if not config.vixsettings.Subservice.value: self.openTimerList() else: self.subserviceSelection() def checkSubservicesAvail(self): serviceRef = self.session.nav.getCurrentlyPlayingServiceReference() if not serviceRef or not hasActiveSubservicesForCurrentChannel(serviceRef.toString()): self["SubserviceQuickzapAction"].setEnabled(False) self.bouquets = self.bsel = self.selectedSubservice = None def nextSubservice(self): self.changeSubservice(+1) def prevSubservice(self): self.changeSubservice(-1) def playSubservice(self, ref): self.session.nav.playService(ref, False) def changeSubservice(self, direction): serviceRef = self.session.nav.getCurrentlyPlayingServiceReference() if serviceRef: subservices = getActiveSubservicesForCurrentChannel(serviceRef.toString()) if subservices and len(subservices) > 1 and serviceRef.toString() in [x[1] for x in subservices]: selection = [x[1] for x in subservices].index(serviceRef.toString()) selection += direction % len(subservices) try: newservice = eServiceReference(subservices[selection][0]) except: newservice = None if newservice and newservice.valid(): self.playSubservice(newservice) def subserviceSelection(self): serviceRef = self.session.nav.getCurrentlyPlayingServiceReference() if serviceRef: subservices = getActiveSubservicesForCurrentChannel(serviceRef.toString()) if subservices and len(subservices) > 1 and serviceRef.toString() in [x[1] for x in subservices]: selection = [x[1] for x in subservices].index(serviceRef.toString()) self.bouquets = self.servicelist and self.servicelist.getBouquetList() if self.bouquets and len(self.bouquets): keys = ["red", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + [""] * (len(subservices) - 10) call_func_title = _("Add to favourites") if config.usage.multibouquet.value: call_func_title = _("Add to bouquet") tlist = [(_("Quick zap"), "quickzap", subservices), (call_func_title, "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + subservices selection += 3 else: tlist = [(_("Quick zap"), "quickzap", subservices), ("--", "")] + subservices keys = ["red", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + [""] * (len(subservices) - 10) selection += 2 self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a sub service..."), list=tlist, selection=selection, keys=keys, skin_name="SubserviceSelection") def subserviceSelected(self, service): if service and len(service) > 1: if service[1] == "quickzap": from Screens.SubservicesQuickzap import SubservicesQuickzap self.session.open(SubservicesQuickzap, service[2]) else: try: ref = eServiceReference(service[1]) except: ref = None if ref and ref.valid(): self["SubserviceQuickzapAction"].setEnabled(True) self.playSubservice(ref) def addSubserviceToBouquetCallback(self, service): if service and len(service) > 1: try: self.selectedSubservice = eServiceReference(service[1]) except: self.selectedSubservice = None if self.selectedSubservice is None or not self.selectedSubservice.valid() or self.bouquets is None: self.bouquets = self.bsel = self.selectedSubservice = None return cnt = len(self.bouquets) if cnt > 1: self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet) elif cnt == 1: self.addSubserviceToBouquet(self.bouquets[0][1]) self.session.open(MessageBox, _("The service has been added to the favourites."), MessageBox.TYPE_INFO, simple=True) def bouquetSelClosed(self, confirmed): self.bouquets = self.bsel = self.selectedSubservice = None if confirmed: self.session.open(MessageBox, _("The service has been added to the selected bouquet."), MessageBox.TYPE_INFO, simple=True) def addSubserviceToBouquet(self, dest): self.servicelist.addServiceToBouquet(dest, self.selectedSubservice) if self.bsel: self.bsel.close(True) self.bouquets = self.bsel = self.selectedSubservice = None def openTimerList(self): self.session.open(TimerEditList) class InfoBarRedButton: def __init__(self): self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions", { "activateRedButton": (self.activateRedButton, _("Red button...")), }, description=_("HbbTV")) self.onHBBTVActivation = [] self.onRedButtonActivation = [] def activateRedButton(self): service = self.session.nav.getCurrentService() info = service and service.info() if info and info.getInfoString(iServiceInformation.sHBBTVUrl) != "": for x in self.onHBBTVActivation: x() elif False: # TODO: other red button services for x in self.onRedButtonActivation: x() class InfoBarTimerButton: def __init__(self): self["TimerButtonActions"] = HelpableActionMap(self, "InfobarTimerButtonActions", { "timerSelection": (self.timerSelection, _("Timer selection...")), }, description=_("Timer control")) def timerSelection(self): from Screens.TimerEdit import TimerEditList self.session.open(TimerEditList) class InfoBarVmodeButton: def __init__(self): self["VmodeButtonActions"] = HelpableActionMap(self, "InfobarVmodeButtonActions", { "vmodeSelection": (self.vmodeSelection, _("Letterbox zoom")), }, description=_("Screen proportions")) def vmodeSelection(self): self.session.open(VideoMode) class VideoMode(Screen): def __init__(self, session): Screen.__init__(self, session) self["videomode"] = Label() self["actions"] = NumberActionMap(["InfobarVmodeButtonActions"], { "vmodeSelection": self.selectVMode }) self.Timer = eTimer() self.Timer.callback.append(self.quit) self.selectVMode() def selectVMode(self): policy = config.av.policy_43 if self.isWideScreen(): policy = config.av.policy_169 idx = policy.choices.index(policy.value) idx = (idx + 1) % len(policy.choices) policy.value = policy.choices[idx] self["videomode"].setText(policy.value) self.Timer.start(1000, True) def isWideScreen(self): from Components.Converter.ServiceInfo import WIDESCREEN service = self.session.nav.getCurrentService() info = service and service.info() return info.getInfo(iServiceInformation.sAspect) in WIDESCREEN def quit(self): self.Timer.stop() self.close() class InfoBarAdditionalInfo: def __init__(self): self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0) self["TimeshiftPossible"] = self["RecordingPossible"] self["ExtensionsAvailable"] = Boolean(fixed=1) # TODO: these properties should be queried from the input device keymap self["ShowTimeshiftOnYellow"] = Boolean(fixed=0) self["ShowAudioOnYellow"] = Boolean(fixed=0) self["ShowRecordOnRed"] = Boolean(fixed=0) class InfoBarNotifications: def __init__(self): self.onExecBegin.append(self.checkNotifications) Notifications.notificationAdded.append(self.checkNotificationsIfExecing) self.onClose.append(self.__removeNotification) def __removeNotification(self): Notifications.notificationAdded.remove(self.checkNotificationsIfExecing) def checkNotificationsIfExecing(self): if self.execing: self.checkNotifications() def checkNotifications(self): notifications = Notifications.notifications if notifications: n = notifications[0] del notifications[0] cb = n[0] if "onSessionOpenCallback" in n[3]: n[3]["onSessionOpenCallback"]() del n[3]["onSessionOpenCallback"] if cb: dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3]) elif not Notifications.current_notifications and n[4] == "ZapError": if "timeout" in n[3]: del n[3]["timeout"] n[3]["enable_input"] = False dlg = self.session.instantiateDialog(n[1], *n[2], **n[3]) self.hide() dlg.show() self.notificationDialog = dlg eActionMap.getInstance().bindAction('', -maxint - 1, self.keypressNotification) else: dlg = self.session.open(n[1], *n[2], **n[3]) # remember that this notification is currently active d = (n[4], dlg) Notifications.current_notifications.append(d) dlg.onClose.append(boundFunction(self.__notificationClosed, d)) def closeNotificationInstantiateDialog(self): if hasattr(self, "notificationDialog"): self.session.deleteDialog(self.notificationDialog) del self.notificationDialog eActionMap.getInstance().unbindAction('', self.keypressNotification) def keypressNotification(self, key, flag): if flag: self.closeNotificationInstantiateDialog() def __notificationClosed(self, d): Notifications.current_notifications.remove(d) class InfoBarServiceNotifications: def __init__(self): self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evEnd: self.serviceHasEnded }) def serviceHasEnded(self): # print "service end!" try: self.setSeekState(self.SEEK_STATE_PLAY) except: pass class InfoBarCueSheetSupport: CUT_TYPE_IN = 0 CUT_TYPE_OUT = 1 CUT_TYPE_MARK = 2 CUT_TYPE_LAST = 3 ENABLE_RESUME_SUPPORT = False def __init__(self, actionmap="InfobarCueSheetActions"): self["CueSheetActions"] = HelpableActionMap(self, actionmap, { "jumpPreviousMark": (self.jumpPreviousMark, _("Jump to the previous marked position")), "jumpNextMark": (self.jumpNextMark, _("Jump to the next marked position")), "toggleMark": (self.toggleMark, _("Toggle a cut mark at the current position")) }, prio=1, description=_("Bookmarks")) self.cut_list = [] self.is_closing = False self.resume_point = None self.force_next_resume = False self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evStart: self.__serviceStarted, iPlayableService.evCuesheetChanged: self.downloadCuesheet, iPlayableService.evStopped: self.__evStopped, }) self.__blockDownloadCuesheet = False self.__recording = None self.__recordingCuts = [] def __evStopped(self): if isMoviePlayerInfoBar(self): if self.__recording and self.__recordingCuts: # resume mark may have been added... self.downloadCuesheet() # Clear marks added from the recording, # They will be added to the .cuts file when the # recording finishes. self.__clearRecordingCuts() self.uploadCuesheet() def __onClose(self): if self.__gotRecordEvent in NavigationInstance.instance.record_event: NavigationInstance.instance.record_event.remove(self.__gotRecordEvent) self.__recording = None __endEvents = ( iRecordableService.evEnd, iRecordableService.evRecordStopped, iRecordableService.evRecordFailed, iRecordableService.evRecordWriteError, iRecordableService.evRecordAborted, iRecordableService.evGstRecordEnded, ) def __gotRecordEvent(self, record, event): if record.getPtrString() != self.__recording.getPtrString(): return if event in self.__endEvents: if self.__gotRecordEvent in NavigationInstance.instance.record_event: NavigationInstance.instance.record_event.remove(self.__gotRecordEvent) # When the recording ends, the mapping of # cut points from time to file offset changes # slightly. Upload the recording cut marks to # catch these changes. self.updateFromRecCuesheet() self.__recording = None elif event == iRecordableService.evNewEventInfo: self.updateFromRecCuesheet() def __serviceStarted(self): if self.is_closing: return self.__findRecording() self.downloadCuesheet() force_resume = self.force_next_resume self.force_next_resume = False self.resume_point = None if self.ENABLE_RESUME_SUPPORT: for (pts, what) in self.cut_list: if what == self.CUT_TYPE_LAST: last = pts break else: last = getResumePoint(self.session) if last is None: return # only resume if at least 10 seconds ahead, or <10 seconds before the end. seekable = self.__getSeekable() if seekable is None: return # Should not happen? length = seekable.getLength() or (None, 0) # Hmm, this implies we don't resume if the length is unknown... if (last > 900000) and (not length[1] or (last < length[1] - 900000)): self.resume_point = last l = last / 90000 if force_resume: self.playLastCB(True) elif "ask" in config.usage.on_movie_start.value or not length[1]: Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume playback?") + "\n" + (_("Resume position at %s") % ("%d:%02d:%02d" % (l / 3600, l % 3600 / 60, l % 60))), timeout=30, default="yes" in config.usage.on_movie_start.value) elif config.usage.on_movie_start.value == "resume": Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO) def __findRecording(self): if isMoviePlayerInfoBar(self): playing = self.session.nav.getCurrentlyPlayingServiceOrGroup() navInstance = NavigationInstance.instance for timer in navInstance.RecordTimer.timer_list: if timer.isRunning() and not timer.justplay and timer.record_service: if playing and playing.getPath() == timer.Filename + timer.record_service.getFilenameExtension(): if self.__gotRecordEvent not in navInstance.record_event: navInstance.record_event.append(self.__gotRecordEvent) self.__recording = timer.record_service self.onClose.append(self.__onClose) break def playLastCB(self, answer): # This can occasionally get called with an empty (new?) self!?! # So avoid the inevitable crash that will follow if we don't check. # if not hasattr(self, "resume_point"): Notifications.AddPopup(text=_("Playback information missing\nPlayback aborted to avoid crash\nPlease retry"), type=MessageBox.TYPE_WARNING, timeout=8) return if answer == True and self.resume_point: self.doSeek(self.resume_point) self.hideAfterResume() def forceNextResume(self, force=True): self.force_next_resume = force def hideAfterResume(self): if isinstance(self, InfoBarShowHide): self.hide() def __getSeekable(self): service = self.session.nav.getCurrentService() if service is None: return None return service.seek() def cueGetCurrentPosition(self): seek = self.__getSeekable() if seek is None: return None r = seek.getPlayPosition() if r[0]: return None return long(r[1]) def cueGetEndCutPosition(self): ret = False isin = True for cp in self.cut_list: if cp[1] == self.CUT_TYPE_OUT: if isin: isin = False ret = cp[0] elif cp[1] == self.CUT_TYPE_IN: isin = True return ret def jumpPreviousNextMark(self, cmp, start=False): current_pos = self.cueGetCurrentPosition() if current_pos is None: return False mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start) if mark is not None: pts = mark[0] else: return False self.doSeek(pts) return True def jumpPreviousMark(self): # we add 5 seconds, so if the play position is <5s after # the mark, the mark before will be used self.jumpPreviousNextMark(lambda x: -x - 5 * 90000, start=True) def jumpNextMark(self): if not self.jumpPreviousNextMark(lambda x: x - 90000): self.doSeek(-1) def getNearestCutPoint(self, pts, cmp=abs, start=False): # can be optimized beforecut = True nearest = None bestdiff = -1 instate = True if start: bestdiff = cmp(0 - pts) if bestdiff >= 0: nearest = [0, False] for cp in self.cut_list: if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT): beforecut = False if cp[1] == self.CUT_TYPE_IN: # Start is here, disregard previous marks diff = cmp(cp[0] - pts) if start and diff >= 0: nearest = cp bestdiff = diff else: nearest = None bestdiff = -1 if cp[1] == self.CUT_TYPE_IN: instate = True elif cp[1] == self.CUT_TYPE_OUT: instate = False elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST): diff = cmp(cp[0] - pts) if instate and diff >= 0 and (nearest is None or bestdiff > diff): nearest = cp bestdiff = diff return nearest def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5 * 90000, onlyreturn=False): current_pos = self.cueGetCurrentPosition() if current_pos is None: # print "not seekable" return nearest_cutpoint = self.getNearestCutPoint(current_pos) if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance: if onlyreturn: return nearest_cutpoint if not onlyadd: self.removeMark(nearest_cutpoint) elif not onlyremove and not onlyreturn: self.addMark((current_pos, self.CUT_TYPE_MARK)) if onlyreturn: return None def addMark(self, point): insort(self.cut_list, point) self.uploadCuesheet() self.showAfterCuesheetOperation() def removeMark(self, point): self.cut_list.remove(point) self.uploadCuesheet() self.showAfterCuesheetOperation() def showAfterCuesheetOperation(self): if isinstance(self, InfoBarShowHide): self.doShow() def __getCuesheet(self): service = self.session.nav.getCurrentService() if service is None: return None return service.cueSheet() def __clearRecordingCuts(self): if self.__recordingCuts: cut_list = [] for point in self.cut_list: if point in self.__recordingCuts: self.__recordingCuts.remove(point) else: cut_list.append(point) self.__recordingCuts = [] self.cut_list = cut_list def uploadCuesheet(self): cue = self.__getCuesheet() if cue is None: # print "upload failed, no cuesheet interface" return self.__blockDownloadCuesheet = True cue.setCutList(self.cut_list) self.__blockDownloadCuesheet = False def downloadCuesheet(self): # Stop cuesheet uploads from causing infinite recursion # through evCuesheetChanged if updateFromRecCuesheet() # does an uploadCuesheet() if self.__blockDownloadCuesheet: return cue = self.__getCuesheet() if cue is None: # print "download failed, no cuesheet interface" self.cut_list = [] else: self.cut_list = cue.getCutList() self.updateFromRecCuesheet() def updateFromRecCuesheet(self): if self.__recording: self.__clearRecordingCuts() rec_cuts = self.__recording.getCutList() for point in rec_cuts: if point not in self.cut_list: insort(self.cut_list, point) self.__recordingCuts.append(point) if self.__recordingCuts: self.uploadCuesheet() class InfoBarSummary(Screen): skin = """ WithSeconds config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean Blink Name Progress """ # for picon: (path="piconlcd" will use LCD picons) # # Reference # class InfoBarSummarySupport: def __init__(self): pass def createSummary(self): return InfoBarSummary class InfoBarMoviePlayerSummary(Screen): skin = """ WithSeconds config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean Blink Name Position """ def __init__(self, session, parent): Screen.__init__(self, session, parent=parent) self["state_summary"] = StaticText("") self["speed_summary"] = StaticText("") self["statusicon_summary"] = MultiPixmap() self.onShow.append(self.addWatcher) self.onHide.append(self.removeWatcher) def addWatcher(self): self.parent.onChangedEntry.append(self.selectionChanged) def removeWatcher(self): self.parent.onChangedEntry.remove(self.selectionChanged) def selectionChanged(self, state_summary, speed_summary, statusicon_summary): self["state_summary"].setText(state_summary) self["speed_summary"].setText(speed_summary) self["statusicon_summary"].setPixmapNum(int(statusicon_summary)) class InfoBarMoviePlayerSummarySupport: def __init__(self): pass def createSummary(self): return InfoBarMoviePlayerSummary class InfoBarTeletextPlugin: def __init__(self): self.teletext_plugin = None for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT): self.teletext_plugin = p if self.teletext_plugin is not None: self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions", { "startTeletext": (self.startTeletext, _("View teletext...")) }, description=_("Teletext")) else: print "[InfoBarGenerics] no teletext plugin found!" def startTeletext(self): self.teletext_plugin and self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService()) class InfoBarSubtitleSupport(object): def __init__(self): object.__init__(self) self["SubtitleSelectionAction"] = HelpableActionMap(self, "InfobarSubtitleSelectionActions", { "subtitleSelection": (self.subtitleSelection, _("Subtitle selection...")), "toggleDefaultSubtitles": (self.toggleDefaultSubtitles, _("Toggle the default subtitles")) }, description=_("Subtitles")) self.selected_subtitle = None if isStandardInfoBar(self): self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay) self.subtitle_window.setAnimationMode(0) else: from Screens.InfoBar import InfoBar self.subtitle_window = InfoBar.instance.subtitle_window self.subtitle_window.hide() self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evStart: self.__serviceChanged, iPlayableService.evEnd: self.__serviceChanged, iPlayableService.evUpdatedInfo: self.__updatedInfo }) self.onClose.append(self.__onClose) def __onClose(self): if isStandardInfoBar(self): self.subtitle_window.doClose() self.subtitle_window = None def getCurrentServiceSubtitle(self): service = self.session.nav.getCurrentService() return service and service.subtitle() def subtitleSelection(self): service = self.session.nav.getCurrentService() subtitle = service and service.subtitle() subtitlelist = subtitle and subtitle.getSubtitleList() if self.selected_subtitle or subtitlelist and len(subtitlelist) > 0: from Screens.AudioSelection import SubtitleSelection self.session.open(SubtitleSelection, self) else: return 0 def doCenterDVBSubs(self): service = self.session.nav.getCurrentlyPlayingServiceReference() servicepath = service and service.getPath() if servicepath and servicepath.startswith("/"): if service.toString().startswith("1:"): info = eServiceCenter.getInstance().info(service) service = info and info.getInfoString(service, iServiceInformation.sServiceref) config.subtitles.dvb_subtitles_centered.value = service and eDVBDB.getInstance().getFlag(eServiceReference(service)) & self.FLAG_CENTER_DVB_SUBS and True return service = self.session.nav.getCurrentService() info = service and service.info() config.subtitles.dvb_subtitles_centered.value = info and info.getInfo(iServiceInformation.sCenterDVBSubs) and True def __serviceChanged(self): if self.selected_subtitle: self.selected_subtitle = None self.subtitle_window.hide() def __updatedInfo(self): if not self.selected_subtitle: subtitle = self.getCurrentServiceSubtitle() cachedsubtitle = subtitle and subtitle.getCachedSubtitle() if cachedsubtitle: self.enableSubtitle(cachedsubtitle) self.doCenterDVBSubs() def toggleDefaultSubtitles(self): subtitle = self.getCurrentServiceSubtitle() subtitlelist = subtitle and subtitle.getSubtitleList() if subtitlelist is None or len(subtitlelist) == 0: self.subtitle_window.showMessage(_("No subtitles available"), True) elif self.selected_subtitle: self.enableSubtitle(None) self.subtitle_window.showMessage(_("Subtitles off"), True) self.selected_subtitle = None else: self.enableSubtitle(subtitlelist[0]) self.subtitle_window.showMessage(_("Subtitles on"), False) def enableSubtitle(self, newSubtitle): if self.selected_subtitle != newSubtitle: subtitle = self.getCurrentServiceSubtitle() self.selected_subtitle = newSubtitle if subtitle and newSubtitle: subtitle.enableSubtitles(self.subtitle_window.instance, newSubtitle) self.subtitle_window.show() self.doCenterDVBSubs() else: if subtitle: subtitle.disableSubtitles(self.subtitle_window.instance) self.subtitle_window.hide() def restartSubtitle(self): if self.selected_subtitle: self.enableSubtitle(self.selected_subtitle) class InfoBarServiceErrorPopupSupport: def __init__(self): self.__event_tracker = ServiceEventTracker(screen=self, eventmap={ iPlayableService.evTuneFailed: self.__tuneFailed, iPlayableService.evTunedIn: self.__serviceStarted, iPlayableService.evStart: self.__serviceStarted }) self.__serviceStarted() def __serviceStarted(self): self.closeNotificationInstantiateDialog() self.last_error = None Notifications.RemovePopup(id="ZapError") def __tuneFailed(self): if not config.usage.hide_zap_errors.value or not config.usage.remote_fallback_enabled.value: service = self.session.nav.getCurrentService() info = service and service.info() error = info and info.getInfo(iServiceInformation.sDVBState) if not config.usage.remote_fallback_enabled.value and (error == eDVBServicePMTHandler.eventMisconfiguration or error == eDVBServicePMTHandler.eventNoResources): self.session.nav.currentlyPlayingServiceReference = None self.session.nav.currentlyPlayingServiceOrGroup = None if error == self.last_error: error = None else: self.last_error = error error = { eDVBServicePMTHandler.eventNoResources: _("No free tuner!"), eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"), eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"), eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"), eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"), eDVBServicePMTHandler.eventNewProgramInfo: None, eDVBServicePMTHandler.eventTuned: None, eDVBServicePMTHandler.eventSOF: None, eDVBServicePMTHandler.eventEOF: None, eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"), }.get(error) #this returns None when the key not exist in the dict if error and not config.usage.hide_zap_errors.value: self.closeNotificationInstantiateDialog() if hasattr(self, "dishDialog") and not self.dishDialog.dishState(): Notifications.AddPopup(text=error, type=MessageBox.TYPE_ERROR, timeout=5, id="ZapError") class InfoBarZoom: def __init__(self): self.zoomrate = 0 self.zoomin = 1 self["ZoomActions"] = HelpableActionMap(self, "InfobarZoomActions", { "ZoomInOut": (self.ZoomInOut, _("Zoom In/Out TV...")), "ZoomOff": (self.ZoomOff, _("Zoom Off...")), }, prio=2, description=_("Zoom")) def ZoomInOut(self): zoomval = 0 if self.zoomrate > 3: self.zoomin = 0 elif self.zoomrate < -9: self.zoomin = 1 if self.zoomin == 1: self.zoomrate += 1 else: self.zoomrate -= 1 if self.zoomrate < 0: zoomval = abs(self.zoomrate) + 10 else: zoomval = self.zoomrate # print "zoomRate:", self.zoomrate # print "zoomval:", zoomval file = open("/proc/stb/vmpeg/0/zoomrate", "w") file.write('%d' % int(zoomval)) file.close() def ZoomOff(self): self.zoomrate = 0 self.zoomin = 1 f = open("/proc/stb/vmpeg/0/zoomrate", "w") f.write(str(0)) f.close() class InfoBarHdmi: def __init__(self): self.hdmi_enabled_full = False self.hdmi_enabled_pip = False if SystemInfo['HasHDMIin']: if not self.hdmi_enabled_full: self.addExtension((self.getHDMIInFullScreen, self.HDMIInFull, lambda: True), "blue") if not self.hdmi_enabled_pip: self.addExtension((self.getHDMIInPiPScreen, self.HDMIInPiP, lambda: True), "green") self["HDMIActions"] = HelpableActionMap(self, "InfobarHDMIActions", { "HDMIin": (self.HDMIIn, _("Switch to HDMI in mode")), "HDMIinLong": (self.HDMIInLong, _("Switch to HDMI in mode")), }, prio=2, description=_("HDMI input")) def HDMIInLong(self): if not hasattr(self.session, 'pip') and not self.session.pipshown: self.session.pip = self.session.instantiateDialog(PictureInPicture) self.session.pip.playService(eServiceReference('8192:0:1:0:0:0:0:0:0:0:')) self.session.pip.show() self.session.pipshown = True else: curref = self.session.pip.getCurrentService() if curref and curref.type != 8192: self.session.pip.playService(eServiceReference('8192:0:1:0:0:0:0:0:0:0:')) else: self.session.pipshown = False del self.session.pip def HDMIIn(self): slist = self.servicelist curref = self.session.nav.getCurrentlyPlayingServiceOrGroup() if curref and curref.type != 8192: self.session.nav.playService(eServiceReference('8192:0:1:0:0:0:0:0:0:0:')) else: self.session.nav.playService(slist.servicelist.getCurrent()) def getHDMIInFullScreen(self): if not self.hdmi_enabled_full: return _("Turn on HDMI-IN full screen mode") else: return _("Turn off HDMI-IN full screen mode") def getHDMIInPiPScreen(self): if not self.hdmi_enabled_pip: return _("Turn on HDMI-IN PiP mode") else: return _("Turn off HDMI-IN PiP mode") def HDMIInPiP(self): if not hasattr(self.session, 'pip') and not self.session.pipshown: self.hdmi_enabled_pip = True self.session.pip = self.session.instantiateDialog(PictureInPicture) self.session.pip.playService(eServiceReference('8192:0:1:0:0:0:0:0:0:0:')) self.session.pip.show() self.session.pipshown = True self.session.pip.servicePath = self.servicelist.getCurrentServicePath() else: curref = self.session.pip.getCurrentService() if curref and curref.type != 8192: self.hdmi_enabled_pip = True self.session.pip.playService(eServiceReference('8192:0:1:0:0:0:0:0:0:0:')) else: self.hdmi_enabled_pip = False self.session.pipshown = False del self.session.pip def HDMIInFull(self): slist = self.servicelist curref = self.session.nav.getCurrentlyPlayingServiceOrGroup() if curref and curref.type != 8192: self.hdmi_enabled_full = True self.session.nav.playService(eServiceReference('8192:0:1:0:0:0:0:0:0:0:')) else: self.hdmi_enabled_full = False self.session.nav.playService(slist.servicelist.getCurrent())