from bisect import insort
from datetime import datetime
from inspect import getfullargspec
from itertools import groupby
from os import listdir
from os.path import exists, isfile, ismount, realpath, splitext
from pickle import HIGHEST_PROTOCOL, dump, load
from re import match
from socket import AF_UNIX, SOCK_STREAM, socket
from sys import maxsize
from time import localtime, strftime, time
from enigma import eActionMap, eAVControl, eDBoxLCD, eDVBDB, eDVBServicePMTHandler, eDVBVolumecontrol, eEPGCache, eServiceCenter, eServiceReference, eTimer, getBsodCounter, getDesktop, iPlayableService, iServiceInformation, quitMainloop, resetBsodCounter, eDVBVolumecontrol
from keyids import KEYFLAGS, KEYIDNAMES, KEYIDS
from RecordTimer import AFTEREVENT, RecordTimer, RecordTimerEntry, findSafeRecordPath, parseEvent
from ServiceReference import ServiceReference, getStreamRelayRef, hdmiInServiceRef, isPlayableForCur
from Components.ActionMap import ActionMap, HelpableActionMap, HelpableNumberActionMap
from Components.AVSwitch import iAVSwitch
from Components.config import ConfigBoolean, ConfigClock, ConfigSelection, config, configfile
from Components.Harddisk import findMountPoint, harddiskmanager
from Components.Input import Input
from Components.Label import Label
from Components.MovieList import AUDIO_EXTENSIONS, DVD_EXTENSIONS, MOVIE_EXTENSIONS
from Components.Pixmap import MovingPixmap, MultiPixmap
from Components.PluginComponent import plugins
from Components.ScrollLabel import ScrollLabel
from Components.ServiceEventTracker import ServiceEventTracker
from Components.SystemInfo import BoxInfo, getBoxDisplayName
from Components.Task import job_manager
from Components.TimerList import TimerList # Deprecated!
from Components.Timeshift import InfoBarTimeshift
from Components.UsageConfig import defaultMoviePath, preferredInstantRecordPath, preferredTimerPath
from Components.VolumeControl import VolumeControl
from Components.Sources.Boolean import Boolean
from Components.Sources.ServiceEvent import ServiceEvent
from Components.Sources.StaticText import StaticText
from Plugins.Plugin import PluginDescriptor
from Screens.ChannelSelection import BouquetSelector, ChannelSelection, EpgBouquetSelector, PiPZapSelection, SilentBouquetSelector, service_types_tv
from Screens.ChoiceBox import ChoiceBox
from Screens.DateTimeInput import InstantRecordingEndTime
from Screens.Dish import Dish
from Screens.EpgSelection import EPGSelection
from Screens.EventView import EventViewEPGSelect, EventViewSimple
from Screens.InputBox import InputBox
from Screens.Menu import Menu, findMenu
from Screens.MessageBox import MessageBox
from Screens.MinuteInput import MinuteInput
from Screens.PictureInPicture import PictureInPicture
from Screens.PiPSetup import PiPSetup
from Screens.PVRState import PVRState, TimeshiftState
from Screens.SubtitleDisplay import SubtitleDisplay
from Screens.RdsDisplay import RassInteractive, RdsInfoDisplay
from Screens.Screen import Screen
from Screens.ScreenSaver import ScreenSaver
from Screens.Setup import Setup
import Screens.Standby
from Screens.Standby import Standby, TryQuitMainloop
from Screens.Timers import RecordTimerEdit, RecordTimerOverview
from Screens.UnhandledKey import UnhandledKey
from Tools import Notifications
from Tools.BoundFunction import boundFunction
from Tools.Directories import SCOPE_CONFIG, SCOPE_SKINS, fileReadLines, fileWriteLines, isPluginInstalled, pathExists, resolveFilename
MODULE_NAME = __name__.split(".")[-1]
AUDIO = False
seek_withjumps_muted = False
jump_pts_adder = 0
jump_last_pts = None
jump_last_pos = None
keyPressCallback = []
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 list(resumePointCache.items()):
if v[0] < lru:
candidate = k
filepath = realpath(candidate.split(":")[-1])
mountpoint = findMountPoint(filepath)
if ismount(mountpoint) and not 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")
dump(resumePointCache, f, HIGHEST_PROTOCOL)
f.close()
except Exception as ex:
print("[InfoBarGenerics] Failed to write resumepoints:", ex)
resumePointCacheLast = int(time())
def loadResumePoints():
try:
file = open("/etc/enigma2/resumepoints.pkl", "rb")
PickleFile = load(file)
file.close()
return PickleFile
except Exception as ex:
print("[InfoBarGenerics] Failed to load resumepoints:", ex)
return {}
def updateresumePointCache():
global resumePointCache
resumePointCache = loadResumePoints()
def ToggleVideo():
mode = open("/proc/stb/video/policy").read()[:-1]
print("[InfoBarGenerics] toggle videomode:", mode)
if mode == "letterbox":
f = open("/proc/stb/video/policy", "w")
f.write("panscan")
f.close()
elif mode == "panscan":
f = open("/proc/stb/video/policy", "w")
f.write("letterbox")
f.close()
else:
# If current policy is not PanScan or Letterbox, set to PanScan.
f = open("/proc/stb/video/policy", "w")
f.write("panscan")
f.close()
resumePointCache = loadResumePoints()
resumePointCacheLast = int(time())
class InfoBarStreamRelay:
FILENAME = "/etc/enigma2/whitelist_streamrelay"
def __init__(self):
self.reload()
def reload(self):
data = fileReadLines(self.FILENAME, default=[], source=self.__class__.__name__)
self.__services = self.__sanitizeData(data)
def __sanitizeData(self, data: list):
return list(set([match(r"([0-9A-F]+:){10}", line.strip()).group(0) for line in data if line and match(r"^(?:[0-9A-F]+:){10}", line.strip())]))
def check(self, nav, service):
return (service or nav.getCurrentlyPlayingServiceReference()) and service.toCompareString() in self.__services
def write(self):
fileWriteLines(self.FILENAME, self.__services, source=self.__class__.__name__)
def toggle(self, nav, service):
if isinstance(service, list):
serviceList = service
serviceList = [service.toCompareString() for service in serviceList]
self.__services = list(set(serviceList + self.__services))
self.write()
else:
service = service or nav.getCurrentlyPlayingServiceReference()
if service:
servicestring = service.toCompareString()
if servicestring in self.__services:
self.__services.remove(servicestring)
else:
self.__services.append(servicestring)
if nav.getCurrentlyPlayingServiceReference() == service:
nav.restartService()
self.write()
def __getData(self):
return self.__services
def __setData(self, value):
self.__services = value
self.write()
data = property(__getData, __setData)
def streamrelayChecker(self, playref):
playrefstring = playref.toCompareString()
if "%3a//" not in playrefstring and playrefstring in self.__services:
url = f'http://{".".join("%d" % d for d in config.misc.softcam_streamrelay_url.value)}:{config.misc.softcam_streamrelay_port.value}/'
if "127.0.0.1" in url:
playrefmod = ":".join([("%x" % (int(x[1], 16) + 1)).upper() if x[0] == 6 else x[1] for x in enumerate(playrefstring.split(":"))])
else:
playrefmod = playrefstring
playref = eServiceReference("%s%s%s:%s" % (playrefmod, url.replace(":", "%3a"), playrefstring.replace(":", "%3a"), ServiceReference(playref).getServiceName()))
print(f"[{self.__class__.__name__}] Play service {playref.toCompareString()} via streamrelay")
playref.setAlternativeUrl(playrefstring)
return playref, True
return playref, False
def checkService(self, service):
return service and service.toCompareString() in self.__services
streamrelay = InfoBarStreamRelay()
class InfoBarAutoCam:
FILENAME = "/etc/enigma2/autocam"
def __init__(self):
self.currentCam = BoxInfo.getItem("CurrentSoftcam")
self.defaultCam = config.misc.autocamDefault.value or self.currentCam
self.reload()
def reload(self):
self.autoCam = {}
items = fileReadLines(self.FILENAME, default=[], source=self.__class__.__name__)
items = [item for item in items if item and "=" in item]
for item in items:
itemValues = item.split("=")
self.autoCam[itemValues[0]] = itemValues[1]
def write(self):
items = []
for key in self.autoCam.keys():
items.append(f"{key}={self.autoCam[key]}")
fileWriteLines(self.FILENAME, lines=items, source=self.__class__.__name__)
def getData(self):
return self.autoCam
def setData(self, value):
self.autoCam = value
self.write()
data = property(getData, setData)
def getCam(self, service):
return self.autoCam.get(service.toCompareString(), None)
def checkCrypt(self, service):
refstring = service.toCompareString()
if refstring.startswith("1:") and "%" not in refstring:
try:
info = eServiceCenter.getInstance().info(service)
return info.isCrypted()
except Exception:
pass
return False
def selectCam(self, nav, service, cam):
service = service or nav.getCurrentlyPlayingServiceReference()
if service:
servicestring = service.toCompareString()
if cam == "None":
if servicestring in self.autoCam:
del self.autoCam[servicestring]
else:
self.autoCam[servicestring] = cam
self.write()
def selectCams(self, services, cam):
for service in services:
servicestring = service.toCompareString()
if cam == "None":
if servicestring in self.autoCam:
del self.autoCam[servicestring]
else:
self.autoCam[servicestring] = cam
self.write()
def autoCamChecker(self, nav, service):
info = service.info()
playrefstring = info.getInfoString(iServiceInformation.sServiceref)
if playrefstring.startswith("1:"):
isStreamRelay = False
if "%" in playrefstring:
playrefstring, isStreamRelay = getStreamRelayRef(playrefstring)
if "%" not in playrefstring and (isStreamRelay or info and info.getInfo(iServiceInformation.sIsCrypted) == 1):
cam = self.autoCam.get(playrefstring, self.defaultCam)
if self.currentCam != cam:
if nav.getRecordings(False):
print("[InfoBarGenerics] InfoBarAutoCam: Switch of Softcam not possible due to an active recording.")
return
self.switchCam(cam)
self.currentCam = cam
BoxInfo.setMutableItem("CurrentSoftcam", cam)
def switchCam(self, new):
deamonSocket = socket(AF_UNIX, SOCK_STREAM)
deamonSocket.connect("/tmp/deamon.socket")
deamonSocket.send(f"SWITCH_SOFTCAM,{new}".encode())
deamonSocket.close()
autocam = InfoBarAutoCam()
class TimerSelection(Screen):
def __init__(self, session, list):
Screen.__init__(self, session)
self.setTitle(_("Timer selection"))
self.list = list
self["timerlist"] = TimerList(self.list)
self["actions"] = HelpableActionMap(self, ["OkCancelActions"], {
"ok": self.selected,
"cancel": self.leave,
}, -1)
def leave(self):
self.close(None)
def selected(self):
self.close(self["timerlist"].getCurrentIndex())
class InfoBarDish:
def __init__(self):
self.dishDialog = self.session.instantiateDialog(Dish)
self.dishDialog.setAnimationMode(0)
class InfoBarLongKeyDetection:
def __init__(self):
eActionMap.getInstance().bindAction("", -maxsize - 1, self.detection) # Highest priority.
self.LongButtonPressed = False
def detection(self, key, flag): # This function is called on every key press!
if flag == 3:
self.LongButtonPressed = True
elif flag == 0:
self.LongButtonPressed = False
class InfoBarUnhandledKey:
def __init__(self):
self.unhandledKey = self.session.instantiateDialog(UnhandledKey)
eActionMap.getInstance().bindAction("", -maxsize - 1, self.processKeyA) # Highest priority.
eActionMap.getInstance().bindAction("", maxsize, self.processKeyB) # Lowest priority.
self.checkUnusedTimer = eTimer()
self.checkUnusedTimer.callback.append(self.isUnhandledKey)
self.flagBitmap = 0b0010
self.prevBitmap = 0b0000
self.sibIgnoreKeys = (
KEYIDS["KEY_VOLUMEDOWN"], # 114.
KEYIDS["KEY_VOLUMEUP"], # 115.
KEYIDS["KEY_INFO"], # 358.
KEYIDS["KEY_OK"], # 352.
KEYIDS["KEY_UP"], # 103.
KEYIDS["KEY_DOWN"], # 108.
KEYIDS["KEY_CHANNELUP"], # 402.
KEYIDS["KEY_CHANNELDOWN"], # 403.
KEYIDS["KEY_NEXT"], #407.
KEYIDS["KEY_PREVIOUS"] # 412.
)
# Flags:
# 0 = Make.
# 1 = Break.
# 2 = Repeat.
# 3 = Long.
# 4 = ASCII.
def processKeyA(self, key, flag): # This function is called on every key press!
print(f"[InfoBarGenerics] Key '{KEYIDNAMES.get(key, _('Unknown'))}' ({key}) {KEYFLAGS.get(flag, _('Unknown'))}.")
for callback in keyPressCallback:
callback()
if self.closeSecondInfoBar(key) and self.secondInfoBarScreen and self.secondInfoBarScreen.shown:
self.secondInfoBarScreen.hide()
self.secondInfoBarWasShown = False
if flag != 4:
if flag == 0:
self.unhandledKey.hide()
if self.flagBitmap & 0b0010: # The button is repeating.
self.flagBitmap = 0b0000
self.prevBitmap = 0b0000
self.flagBitmap |= (1 << flag)
if flag == 1:
self.checkUnusedTimer.start(0, True)
return 0
def processKeyB(self, key, flag): # This function is only called when no other action has handled this key.
if flag != 4:
self.prevBitmap |= (1 << flag)
def closeSecondInfoBar(self, key):
return key >= 12 and key not in self.sibIgnoreKeys
def isUnhandledKey(self):
if self.flagBitmap == self.prevBitmap:
self.unhandledKey.show()
def showUnhandledKey(self):
self.unhandledKey.show()
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)
self.onLayoutFinish.append(self.__layoutFinished)
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 ref[2] == "A" or 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"):
try:
self.pvrStateDialog.hide()
except Exception:
pass
self.screensaver.show()
eActionMap.getInstance().bindAction("", -maxsize - 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):
skin = """""" % (getDesktop(0).size().width(), getDesktop(0).size().height() / 360)
def __init__(self, session):
Screen.__init__(self, session)
class SecondInfoBar(Screen):
ADD_TIMER = 0
REMOVE_TIMER = 1
def __init__(self, session):
Screen.__init__(self, session)
if config.usage.show_second_infobar.value == "3":
self.skinName = "SecondInfoBarECM"
else:
self.skinName = "SecondInfoBar"
self["epg_description"] = ScrollLabel()
self["FullDescription"] = 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"], {
"pageUp": (self.pageUp, _("Switch EPG Page Up")),
"pageDown": (self.pageDown, _("Switch EPG Page Down")),
"prevPage": (self.pageUp, _("Switch EPG Page Up")),
"nextPage": (self.pageDown, _("Switch EPG Page Down")),
"prevEvent": (self.prevEvent, _("Switch to previous EPG Event")),
"nextEvent": (self.nextEvent, _("Switch to next EPG Event")),
"timerAdd": (self.timerAdd, _("Add Timer")),
"openSimilarList": (self.openSimilarList, _("Open Similar List Channel List")),
}, prio=-1, description=_("2nd InfoBar Actions"))
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()
self["FullDescription"].pageUp()
def pageDown(self):
self["epg_description"].pageDown()
self["FullDescription"].pageDown()
def __Show(self):
if config.plisettings.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["FullDescription"].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 display.
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.ref.toString()
for timer in self.session.nav.RecordTimer.timer_list:
if timer.eit == eventid and timer.service_ref.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())
break
else:
newEntry = RecordTimerEntry(self.currentService, afterEvent=AFTEREVENT.AUTO, justplay=False, always_zap=False, checkOldTimers=True, dirname=preferredTimerPath(), *parseEvent(self.event))
self.session.openWithCallback(self.finishedAdd, RecordTimerEdit, newEntry)
def finishedAdd(self, answer):
# print("finished add")
if not isinstance(answer, bool) and answer[0]:
entry = answer[1]
simulTimerList = self.session.nav.RecordTimer.record(entry)
if simulTimerList is not None:
for x in simulTimerList:
if x.setAutoincreaseEnd(entry):
self.session.nav.RecordTimer.timeChanged(x)
simulTimerList = self.session.nav.RecordTimer.record(entry)
if simulTimerList is not None:
if not entry.repeated and not config.recording.margin_before.value and not config.recording.margin_after.value and len(simulTimerList) > 1:
change_time = False
conflict_begin = simulTimerList[1].begin
conflict_end = simulTimerList[1].end
if conflict_begin == entry.end:
entry.end -= 30
change_time = True
elif entry.begin == conflict_end:
entry.begin += 30
change_time = True
if change_time:
simulTimerList = self.session.nav.RecordTimer.record(entry)
if simulTimerList is not None:
self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList)
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
# print("Timeredit aborted")
def finishSanityCorrection(self, answer):
self.finishedAdd(answer)
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 Exception:
pass
description = event.getShortDescription()
extended = event.getExtendedDescription()
if description and extended:
description += "\n"
elif description and not extended:
extended = description
if description == extended:
text = description
else:
text = description + extended
self.setTitle(event.getEventName())
self["epg_description"].setText(text)
self["FullDescription"].setText(extended)
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(EPGSelection, refstr, None, 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
skipToggleShow = False
def __init__(self):
self["ShowHideActions"] = HelpableActionMap(self, ["InfobarShowHideActions"],
{
"LongOKPressed": (self.toggleShowLong, _("Toggle display of the InfoBar")),
"toggleShow": (self.OkPressed, _("Toggle display of the InfoBar")),
"hide": (self.keyHide, _("Hide the InfoBar")),
}, prio=1, description=_("InfoBar Show/Hide Actions")) # Lower priority 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.autocamTimer = eTimer()
self.autocamTimer.timeout.get().append(self.checkAutocam)
self.autocamTimer_active = 0
self.DimmingTimer = eTimer()
self.DimmingTimer.callback.append(self.doDimming)
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.hideVBILineScreen = self.session.instantiateDialog(HideVBILine)
self.hideVBILineScreen.show()
self.onShowHideNotifiers = []
self.standardInfoBar = False
self.lastSecondInfoBar = 0
self.lastResetAlpha = True
self.secondInfoBarScreen = ""
if isStandardInfoBar(self):
self.SwitchSecondInfoBarScreen()
self.onLayoutFinish.append(self.__layoutFinished)
self.onExecBegin.append(self.__onExecBegin)
for plugin in plugins.getPlugins(PluginDescriptor.WHERE_INFOBARLOADED):
plugin(reason=1, session=self.session, instance=self, typeInfoBar=self.__class__.__name__)
self.onClose.append(self.__onClose)
def __onClose(self):
for plugin in plugins.getPlugins(PluginDescriptor.WHERE_INFOBARLOADED):
plugin(reason=0, session=self.session, instance=self, typeInfoBar=self.__class__.__name__)
def __onExecBegin(self):
self.showHideVBI()
def __layoutFinished(self):
if self.secondInfoBarScreen:
self.secondInfoBarScreen.hide()
self.standardInfoBar = True
self.secondInfoBarWasShown = False
self.EventViewIsShown = False
self.hideVBILineScreen.hide()
try:
if self.pvrStateDialog:
pass
except Exception:
self.pvrStateDialog = None
def OkPressed(self):
if config.usage.okbutton_mode.value == "0":
self.toggleShow()
elif config.usage.okbutton_mode.value == "1":
try:
self.openServiceList()
except Exception:
self.toggleShow()
def SwitchSecondInfoBarScreen(self):
if self.lastSecondInfoBar == int(config.usage.show_second_infobar.value):
return
self.secondInfoBarScreen = self.session.instantiateDialog(SecondInfoBar)
self.lastSecondInfoBar = int(config.usage.show_second_infobar.value)
def LongOKPressed(self):
if isinstance(self, InfoBarEPG):
if config.plisettings.InfoBarEpg_mode.value == "1":
self.openInfoBarEPG()
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 exists("/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 keyHide(self, SHOW=True):
if self.__state == self.STATE_HIDDEN:
ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
if ref:
ref = ref.toString()
else:
ref = " "
if SHOW and config.plisettings.InfoBarEpg_mode.value == "2" and not ref[1:].startswith(":0:0:0:0:0:0:0:0:0:"):
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"):
try:
self.pvrStateDialog.hide()
except Exception:
pass
def hidePipOnExitCallback(self, answer):
if answer:
self.showPiP()
def connectShowHideNotifier(self, fnc):
if fnc not 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 self.autocamTimer_active == 1:
self.autocamTimer.stop()
self.autocamTimer.start(1000)
self.autocamTimer_active = 1
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()
idx = config.usage.infobar_timeout.index
if idx:
self.hideTimer.start(idx * 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()
idx = config.usage.second_infobar_timeout.index
if idx:
self.hideTimer.start(idx * 1000, True)
elif hasattr(self, "pvrStateDialog"):
self.hideTimer.stop()
# idx = config.usage.infobar_timeout.index
# if idx:
# self.hideTimer.start(idx*1000, True)
self.skipToggleShow = False
def doShow(self):
self.show()
self.hideTimer.stop()
self.DimmingTimer.stop()
self.doWriteAlpha(config.av.osd_alpha.value)
self.startHideTimer()
def doTimerHide(self):
self.hideTimer.stop()
self.DimmingTimer.start(300, True)
self.dimmed = config.usage.show_infobar_dimming_speed.value
self.skipToggleShow = False
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 Exception:
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 Exception:
# pass
def toggleShow(self):
if self.skipToggleShow:
self.skipToggleShow = False
return
if not hasattr(self, "LongButtonPressed"):
self.LongButtonPressed = False
if not self.LongButtonPressed:
if self.__state == self.STATE_HIDDEN:
if not self.secondInfoBarWasShown or (config.usage.show_second_infobar.value == "1" and not self.EventViewIsShown):
self.show()
if self.secondInfoBarScreen:
self.secondInfoBarScreen.hide()
self.secondInfoBarWasShown = False
self.EventViewIsShown = False
elif self.secondInfoBarScreen and (config.usage.show_second_infobar.value == "2" or config.usage.show_second_infobar.value == "3") and not self.secondInfoBarScreen.shown:
self.SwitchSecondInfoBarScreen()
self.hide()
self.secondInfoBarScreen.show()
self.secondInfoBarWasShown = True
self.startHideTimer()
elif (config.usage.show_second_infobar.value == "1" or isMoviePlayerInfoBar(self)) and not self.EventViewIsShown:
self.hide()
try:
self.openEventView()
except Exception:
pass
self.EventViewIsShown = True
self.hideTimer.stop()
elif isMoviePlayerInfoBar(self) and not self.EventViewIsShown and config.usage.show_second_infobar.value:
self.hide()
self.openEventView(True)
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 Exception:
pass
self.EventViewIsShown = False
def toggleShowLong(self):
try:
if self.LongButtonPressed:
if isinstance(self, InfoBarEPG):
if config.plisettings.InfoBarEpg_mode.value == "1":
self.openInfoBarEPG()
except Exception as e:
print("[InfoBarGenerics] 'toggleShowLong' failed:", e)
def lockShow(self):
try:
self.__locked += 1
except Exception:
self.__locked = 0
if self.execing:
self.show()
self.hideTimer.stop()
self.skipToggleShow = False
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 Exception:
self.__locked = 0
if self.__locked < 0:
self.__locked = 0
if self.execing:
self.startHideTimer()
def openEventView(self, simple=False):
try:
if self.servicelist is None:
return
except Exception:
simple = True
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:
if not simple:
self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
self.dlg_stack.append(self.eventView)
else:
self.eventView = self.session.openWithCallback(self.closed, EventViewSimple, epglist[0], ServiceReference(ref))
self.dlg_stack = None
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 closed(self, ret=False):
if not self.dlg_stack:
return
closedScreen = self.dlg_stack.pop()
if self.eventView and closedScreen == self.eventView:
self.eventView = None
if ret is True or ret == "close":
dlgs = len(self.dlg_stack)
if dlgs > 0:
self.dlg_stack[dlgs - 1].close(dlgs > 1)
self.reopen(ret)
def eventViewCallback(self, setEvent, setService, val): # Used for Now/Next display.
epglist = self.epglist
if len(epglist) > 1:
tmp = epglist[0]
epglist[0] = epglist[1]
epglist[1] = tmp
setEvent(epglist[0])
def checkHideVBI(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)
FLAG_HIDE_VBI = 512
return service and eDVBDB.getInstance().getFlag(eServiceReference(service)) & FLAG_HIDE_VBI and True
else:
return ".hidevbi." in servicepath.lower()
service = self.session.nav.getCurrentService()
info = service and service.info()
return info and info.getInfo(iServiceInformation.sHideVBI) == 1
def showHideVBI(self):
if self.checkHideVBI():
self.hideVBILineScreen.show()
else:
self.hideVBILineScreen.hide()
def checkStreamrelay(self, service=None):
return streamrelay.check(self.session.nav, service)
def checkCrypt(self, service=None):
return autocam.checkCrypt(service)
def checkAutocam(self):
self.autocamTimer.stop()
self.autocamTimer_active = 0
if config.misc.autocamEnabled.value:
service = self.session.nav.getCurrentService()
if service:
autocam.autoCamChecker(self.session.nav, service)
class BufferIndicator(Screen):
def __init__(self, session):
Screen.__init__(self, session)
self["status"] = Label()
self.mayShow = False
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:
service = self.session.nav.getCurrentService()
info = service and service.info()
if info:
value = info.getInfo(iServiceInformation.sBuffer)
if value and value != 100:
self["status"].setText(_("Buffering %d%%") % value)
if not self.shown:
self.show()
def __evStart(self):
self.mayShow = True
self.hide()
def __evGstreamerPlayStarted(self):
self.mayShow = False
self.hide()
class InfoBarBuffer():
def __init__(self):
self.bufferScreen = self.session.instantiateDialog(BufferIndicator)
self.bufferScreen.hide()
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()), recursive=True)
self["servicename"].setText(ServiceReference(self.service).getServiceName())
if not self.startBouquet:
self.startBouquet = self.bouquet
def keyBlue(self):
self.Timer.start(3000, 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())
def keyNumberGlobal(self, number):
if config.usage.numzaptimeoutmode.value != "off":
if config.usage.numzaptimeoutmode.value == "standard":
self.Timer.start(1000, True)
else:
self.Timer.start(config.usage.numzaptimeout2.value, True)
self.numberString += str(number)
self["number"].setText(self.numberString)
self["servicenumber"].setText(self.numberString)
self["number_summary"].setText(self.numberString)
self.field = self.numberString
self.handleServiceName()
self["service_summary"].setText(self["servicename"].getText())
if config.usage.numzappicon.value:
self.showPicon()
if len(self.numberString) >= int(config.usage.maxchannelnumlen.value):
if self.Timer.isActive():
self.Timer.stop()
self.Timer.start(100, True)
def showPicon(self):
self["Service"].newService(self.service)
def __init__(self, session, number, searchNumberFunction=None):
Screen.__init__(self, session)
if config.usage.numzappicon.value:
self.onLayoutFinish.append(self.showPicon)
self.skinName = ["NumberZapPicon", "NumberZapWithName"]
self.onChangedEntry = []
self.numberString = str(number)
self.field = str(number)
self.searchNumber = searchNumberFunction
self.startBouquet = None
self["channel"] = Label(_("Channel:"))
self["channel_summary"] = StaticText(_("Channel:"))
self["number"] = Label(self.numberString)
self["servicenumber"] = Label(self.numberString)
self["number_summary"] = StaticText(self.numberString)
self["servicename"] = Label()
self["service_summary"] = StaticText("")
self["Service"] = ServiceEvent()
self.handleServiceName()
self["service_summary"].setText(self["servicename"].getText())
self["actions"] = HelpableNumberActionMap(self, ["SetupActions", "ShortcutActions"], {
"cancel": (self.quit, _("Cancel selection")),
"ok": (self.keyOK, _("Select/Zap to selected service")),
"blue": (self.keyBlue, _("Toggle service name display")),
"1": (self.keyNumberGlobal, _("Digit entry for service selection")),
"2": (self.keyNumberGlobal, _("Digit entry for service selection")),
"3": (self.keyNumberGlobal, _("Digit entry for service selection")),
"4": (self.keyNumberGlobal, _("Digit entry for service selection")),
"5": (self.keyNumberGlobal, _("Digit entry for service selection")),
"6": (self.keyNumberGlobal, _("Digit entry for service selection")),
"7": (self.keyNumberGlobal, _("Digit entry for service selection")),
"8": (self.keyNumberGlobal, _("Digit entry for service selection")),
"9": (self.keyNumberGlobal, _("Digit entry for service selection")),
"0": (self.keyNumberGlobal, _("Digit entry for service selection"))
}, prio=0, description=_("Service Selection/Zap Actions"))
self.Timer = eTimer()
self.Timer.callback.append(self.keyOK)
if config.usage.maxchannelnumlen.value == "1":
self.Timer.start(100, True)
elif config.usage.numzaptimeoutmode.value != "off":
if config.usage.numzaptimeoutmode.value == "standard":
self.Timer.start(3000, True)
else:
self.Timer.start(config.usage.numzaptimeout1.value, True)
class InfoBarNumberZap:
""" Handles an initial number for NumberZapping """
def __init__(self):
self["NumberActions"] = HelpableNumberActionMap(self, ["NumberActions"], {
"1": (self.keyNumberGlobal, _("Digit entry for service selection")),
"2": (self.keyNumberGlobal, _("Digit entry for service selection")),
"3": (self.keyNumberGlobal, _("Digit entry for service selection")),
"4": (self.keyNumberGlobal, _("Digit entry for service selection")),
"5": (self.keyNumberGlobal, _("Digit entry for service selection")),
"6": (self.keyNumberGlobal, _("Digit entry for service selection")),
"7": (self.keyNumberGlobal, _("Digit entry for service selection")),
"8": (self.keyNumberGlobal, _("Digit entry for service selection")),
"9": (self.keyNumberGlobal, _("Digit entry for service selection")),
"0": (self.keyNumberGlobal, _("Digit entry for service selection"))
}, prio=0, description=_("Service Zap Actions"))
def keyNumberGlobal(self, number):
if "PTSSeekPointer" in self.pvrStateDialog and self.timeshiftEnabled() and self.isSeekable():
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
seekable = self.getSeek()
if seekable:
length = seekable.getLength() or (None, 0)
if length[1] > 0:
key = int(number)
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]
time = time * 90000
seekable.seekRelative(time < 0 and -1 or 1, abs(time))
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 or config.usage.panicbutton.value:
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:
self.service_types = service_types_tv
bqrootstr = "%s FROM BOUQUET \"userbouquet.favourites.tv\" ORDER BY bouquet" % self.service_types
serviceHandler = eServiceCenter.getInstance()
rootbouquet = eServiceReference(bqrootstr)
bouquet = eServiceReference(bqrootstr)
bouquetlist = serviceHandler.list(bouquet)
if bouquetlist is not None:
while True:
bouquet = bouquetlist.getNext()
if bouquet.flags & eServiceReference.isDirectory:
self.servicelist.clearPath()
self.servicelist.setRoot(bouquet)
servicelist = serviceHandler.list(bouquet)
if servicelist is not None:
serviceIterator = servicelist.getNext()
while serviceIterator.valid():
service, bouquet2 = self.searchNumber(config.usage.panicchannel.value)
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()
self.selectAndStartService(service, bouquet)
else:
self.servicelist.recallPrevService()
def numberEntered(self, service=None, bouquet=None):
if service:
self.selectAndStartService(service, bouquet)
def searchNumberHelperRecursive(self, serviceHandler, num, bouquet):
# print("searchNumberHelperRecursive %s" % bouquet.toString())
servicelist = serviceHandler.list(bouquet)
if servicelist:
serviceIterator = servicelist.getNext()
while serviceIterator.valid():
if num == serviceIterator.getChannelNum():
return (serviceIterator, "%s;" % bouquet.toString())
if serviceIterator.flags & eServiceReference.isDirectory:
result = self.searchNumberHelperRecursive(serviceHandler, num, serviceIterator)
if result[0]:
return (result[0], "%s;%s" % (bouquet.toString(), result[1]))
serviceIterator = servicelist.getNext()
return (None, None)
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, recursive=False):
servicepath = 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:
if recursive:
service, servicepath = self.searchNumberHelperRecursive(serviceHandler, number, bouquet)
else:
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()
if servicepath:
return service, "%s;%s" % (self.servicelist.bouquet_root.toString(), servicepath)
else:
return service, bouquet
def selectAndStartService(self, service, bouquet):
if service:
if isinstance(bouquet, str):
self.servicelist.lastroot.value = bouquet
self.servicelist.restoreRoot()
elif 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 the service list.
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
if config.misc.initialchannelselection.value:
self.onShown.append(self.firstRun)
self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection", {
"switchChannelUp": (self.UpPressed, _("Open service list and select previous channel")),
"switchChannelDown": (self.DownPressed, _("Open service list and select next channel")),
"switchChannelUpLong": (self.switchChannelUp, _("Open service list and select previous channel for PiP")),
"switchChannelDownLong": (self.switchChannelDown, _("Open service list and select next channel for PiP")),
"zapUp": (self.zapUp, _("Switch to previous channel")),
"zapDown": (self.zapDown, _("Switch next channel")),
"historyBack": (self.historyBack, _("Switch to previous channel in history")),
"historyNext": (self.historyNext, _("Switch to next channel in history")),
"openServiceList": (self.openServiceList, _("Open service list")),
"openSatellites": (self.openSatellites, _("Open satellites list")),
"openBouquets": (self.openBouquets, _("Open favorites list")),
"LeftPressed": self.LeftPressed,
"RightPressed": self.RightPressed,
"ChannelPlusPressed": self.ChannelPlusPressed,
"ChannelMinusPressed": self.ChannelMinusPressed,
"ChannelPlusPressedLong": self.ChannelPlusPressed,
"ChannelMinusPressedLong": self.ChannelMinusPressed,
}, prio=0, description=_("Service Selection Actions"))
def firstRun(self):
self.onShown.remove(self.firstRun)
config.misc.initialchannelselection.value = False
config.misc.initialchannelselection.save()
self.openServiceList()
def LeftPressed(self):
if config.plisettings.InfoBarEpg_mode.value == "3":
self.openInfoBarEPG()
else:
self.zapUp()
def RightPressed(self):
if config.plisettings.InfoBarEpg_mode.value == "3":
self.openInfoBarEPG()
else:
self.zapDown()
def UpPressed(self):
if config.usage.updownbutton_mode.value == "0":
self.zapDown()
elif config.usage.updownbutton_mode.value == "1":
self.switchChannelUp()
def DownPressed(self):
if config.usage.updownbutton_mode.value == "0":
self.zapUp()
elif config.usage.updownbutton_mode.value == "1":
self.switchChannelDown()
def ChannelPlusPressed(self):
if config.usage.channelbutton_mode.value == "0":
self.zapDown()
elif config.usage.channelbutton_mode.value == "1" or config.usage.channelbutton_mode.value == "3":
self.openServiceList()
elif config.usage.channelbutton_mode.value == "2":
self.serviceListType = "Norm"
self.servicelist.showFavourites()
self.session.execDialog(self.servicelist)
def ChannelMinusPressed(self):
if config.usage.channelbutton_mode.value == "0":
self.zapUp()
elif config.usage.channelbutton_mode.value == "1" or config.usage.channelbutton_mode.value == "3":
self.openServiceList()
elif config.usage.channelbutton_mode.value == "2":
self.serviceListType = "Norm"
self.servicelist.showFavourites()
self.session.execDialog(self.servicelist)
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):
if not self.secondInfoBarScreen or not self.secondInfoBarScreen.shown:
self.keyHide(False)
if not self.LongButtonPressed or BoxInfo.getItem("NumVideoDecoders", 1) <= 1:
if not config.usage.show_bouquetalways.value:
if "keep" not in config.usage.servicelist_cursor_behavior.value:
self.servicelist.moveUp()
self.session.execDialog(self.servicelist)
else:
self.servicelist.showFavourites()
self.session.execDialog(self.servicelist)
elif self.LongButtonPressed:
if not config.usage.show_bouquetalways.value:
if "keep" not in config.usage.servicelist_cursor_behavior.value:
self.servicelist2.moveUp()
self.session.execDialog(self.servicelist2)
else:
self.servicelist2.showFavourites()
self.session.execDialog(self.servicelist2)
def switchChannelDown(self):
if not self.secondInfoBarScreen or not self.secondInfoBarScreen.shown:
self.keyHide(False)
if not self.LongButtonPressed or BoxInfo.getItem("NumVideoDecoders", 1) <= 1:
if not config.usage.show_bouquetalways.value:
if "keep" not in config.usage.servicelist_cursor_behavior.value:
self.servicelist.moveDown()
self.session.execDialog(self.servicelist)
else:
self.servicelist.showFavourites()
self.session.execDialog(self.servicelist)
elif self.LongButtonPressed:
if not config.usage.show_bouquetalways.value:
if "keep" not in config.usage.servicelist_cursor_behavior.value:
self.servicelist2.moveDown()
self.session.execDialog(self.servicelist2)
else:
self.servicelist2.showFavourites()
self.session.execDialog(self.servicelist2)
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 openSubservices(self):
self.servicelist.enterSubservices()
self.session.execDialog(self.servicelist)
def zapUp(self):
if not self.LongButtonPressed or BoxInfo.getItem("NumVideoDecoders", 1) <= 1:
if self.pts_blockZap_timer.isActive():
return
self["SeekActionsPTS"].setEnabled(False)
if self.servicelist.inBouquet():
prev = self.servicelist.getCurrentSelection()
if prev:
isIPTV = "://" in prev.getPath() # Workaround: Ignore IPTV channel streaming.
prev = prev.toString()
while True:
if config.usage.quickzap_bouquet_change.value and self.servicelist.atBegin():
self.servicelist.prevBouquet()
self.servicelist.moveEnd()
else:
self.servicelist.moveUp()
cur = self.servicelist.getCurrentSelection()
if cur:
if self.servicelist.dopipzap:
isPlayable = isIPTV or self.session.pip.isPlayableForPipService(cur)
else:
isPlayable = isIPTV or isPlayableForCur(cur)
if cur and (cur.toString() == prev or isPlayable):
break
else:
self.servicelist.moveUp()
self.servicelist.zap(enable_pipzap=True)
elif self.LongButtonPressed:
if not hasattr(self.session, "pip") and not self.session.pipshown:
self.session.open(MessageBox, _("Please open Picture in Picture first"), MessageBox.TYPE_ERROR)
return
from Screens.ChannelSelection import ChannelSelection
ChannelSelectionInstance = ChannelSelection.instance
ChannelSelectionInstance.dopipzap = True
if self.servicelist2.inBouquet():
prev = self.servicelist2.getCurrentSelection()
if prev:
isIPTV = "://" in prev.getPath() # Workaround: Ignore IPTV channel streaming.
prev = prev.toString()
while True:
if config.usage.quickzap_bouquet_change.value and self.servicelist2.atBegin():
self.servicelist2.prevBouquet()
self.servicelist2.moveEnd()
else:
self.servicelist2.moveUp()
cur = self.servicelist2.getCurrentSelection()
if cur:
if ChannelSelectionInstance.dopipzap:
isPlayable = isIPTV or self.session.pip.isPlayableForPipService(cur)
else:
isPlayable = isIPTV or isPlayableForCur(cur)
if cur and (cur.toString() == prev or isPlayable):
break
else:
self.servicelist2.moveUp()
self.servicelist2.zap(enable_pipzap=True)
ChannelSelectionInstance.dopipzap = False
if self.timeshiftEnabled() and self.isSeekable():
self["SeekActionsPTS"].setEnabled(True)
def zapDown(self):
if not self.LongButtonPressed or BoxInfo.getItem("NumVideoDecoders", 1) <= 1:
if self.pts_blockZap_timer.isActive():
return
self["SeekActionsPTS"].setEnabled(False)
if self.servicelist.inBouquet():
prev = self.servicelist.getCurrentSelection()
if prev:
isIPTV = "://" in prev.getPath() # Workaround: Ignore IPTV channel streaming.
prev = prev.toString()
while True:
if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
self.servicelist.nextBouquet()
self.servicelist.moveTop()
else:
self.servicelist.moveDown()
cur = self.servicelist.getCurrentSelection()
if cur:
if self.servicelist.dopipzap:
isPlayable = isIPTV or self.session.pip.isPlayableForPipService(cur)
else:
isPlayable = isIPTV or isPlayableForCur(cur)
if cur and (cur.toString() == prev or isPlayable):
break
else:
self.servicelist.moveDown()
self.servicelist.zap(enable_pipzap=True)
elif self.LongButtonPressed:
if not hasattr(self.session, "pip") and not self.session.pipshown:
self.session.open(MessageBox, _("Please open Picture in Picture first"), MessageBox.TYPE_ERROR)
return
from Screens.ChannelSelection import ChannelSelection
ChannelSelectionInstance = ChannelSelection.instance
ChannelSelectionInstance.dopipzap = True
if self.servicelist2.inBouquet():
prev = self.servicelist2.getCurrentSelection()
if prev:
isIPTV = "://" in prev.getPath() # Workaround: Ignore IPTV channel streaming.
prev = prev.toString()
while True:
if config.usage.quickzap_bouquet_change.value and self.servicelist2.atEnd():
self.servicelist2.nextBouquet()
self.servicelist2.moveTop()
else:
self.servicelist2.moveDown()
cur = self.servicelist2.getCurrentSelection()
if cur:
if ChannelSelectionInstance.dopipzap:
isPlayable = isIPTV or self.session.pip.isPlayableForPipService(cur)
else:
isPlayable = isIPTV or isPlayableForCur(cur)
if cur and (cur.toString() == prev or isPlayable):
break
else:
self.servicelist2.moveDown()
self.servicelist2.zap(enable_pipzap=True)
ChannelSelectionInstance.dopipzap = False
if self.timeshiftEnabled() and self.isSeekable():
self["SeekActionsPTS"].setEnabled(True)
class InfoBarMenu:
""" Handles a menu action, to open the (main) menu """
def __init__(self):
# "MenuActions" is also used by EMC.
self["MenuActions"] = HelpableActionMap(self, ["InfoBarMenuActions"], {
"showMenu": (self.showMainMenu, _("Enter main menu...")),
"showSetup": (self.showSetupMenu, _("Show setup menu...")),
"showNetworkSetup": (self.showNetworkMenu, _("Show network setup menu...")),
"showSystemSetup": (self.showSystemMenu, _("Show usage and GUI menu...")),
"showHDMIRecord": (self.showHDMIRecordSetup, _("Show HDMIRecord setup...")),
"showRFmod": (self.showRFSetup, _("Show RFmod setup...")),
"toggleAspectRatio": (self.toggleAspectRatio, _("Toggle aspect ratio...")),
}, prio=0, description=_("Menu Actions"))
self.session.infobar = None
def showMainMenu(self):
# print("[InfoBarGenerics] Loading menu XML...")
menu = findMenu("mainmenu")
if menu:
self.session.infobar = self
# So we can access the currently active InfoBar from screens opened from
# within the menu at the moment used from the SubserviceSelection.
self.session.openWithCallback(self.showMenuCallback, Menu, menu)
def showMenuCallback(self, *val):
self.session.infobar = None
def showSetupMenu(self):
menu = findMenu("setup")
if menu:
self.session.openWithCallback(self.showMenuCallback, Menu, menu)
def showNetworkMenu(self):
menu = findMenu("network")
if menu:
self.session.openWithCallback(self.showMenuCallback, Menu, menu)
def showSystemMenu(self):
menu = findMenu("system")
if menu:
self.session.openWithCallback(self.showMenuCallback, Menu, menu)
def showHDMIRecordSetup(self):
if BoxInfo.getItem("HDMIin"):
self.session.openWithCallback(self.showMenuCallback, Setup, "HDMIRecord")
def showRFSetup(self):
if BoxInfo.getItem("RfModulator"):
self.session.openWithCallback(self.showMenuCallback, Setup, "RFmod")
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, _("A/V aspect ratio is '%s'.") % ASPECT_MSG[config.av.aspect.value], MessageBox.TYPE_INFO, timeout=5)
class InfoBarSimpleEventView:
""" Opens the Eventview for now/next """
def __init__(self):
self["EventViewActions"] = HelpableActionMap(self, "InfobarEPGActions", {
"showEventInfo": (self.openEventView, _("Show event details")),
"InfoPressed": (self.openEventView, _("Show event details")),
"showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
}, prio=0, description=_("InfoBar Event View Actions"))
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:
if not simple:
self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
else:
self.eventView = self.session.openWithCallback(self.closed, EventViewSimple, epglist[0], ServiceReference(ref))
self.dlg_stack.append(self.eventView)
def eventViewCallback(self, setEvent, setService, val): # Used for Now/Next display.
epglist = self.epglist
if len(epglist) > 1:
tmp = epglist[0]
epglist[0] = epglist[1]
epglist[1] = tmp
setEvent(epglist[0])
def showEventInfoWhenNotVisible(self):
if self.shown:
self.openEventView()
else:
self.toggleShow()
return 1
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.dlg_stack = []
self.bouquetSel = None
self.eventView = None
self.isInfo = None
self.epglist = []
self.defaultGuideType = self.getDefaultGuidetype()
self.__event_tracker = ServiceEventTracker(screen=self, eventmap={
iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
})
self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", {
"IPressed": (self.IPressed, _("show program information...")),
"InfoPressed": (self.InfoPressed, _("show program information...")),
"showEventInfoPlugin": (self.showEventInfoPlugins, _("List EPG functions...")),
"EPGPressed": (self.EPGPressed, _("show EPG...")),
"showEventGuidePlugin": (self.showEventGuidePlugins, _("List EPG functions...")),
"showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
}, prio=0, description=_("InfoBar EPG Actions"))
def getEPGPluginList(self):
pluginlist = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EVENTINFO)]
if pluginlist:
pluginlist.append((_("Event Info"), self.openEventView))
pluginlist.append((_("Graphical EPG"), self.openGraphEPG))
pluginlist.append((_("Vertical EPG"), self.openVerticalEPG))
pluginlist.append((_("InfoBar EPG"), self.openInfoBarEPG))
pluginlist.append((_("Multi EPG"), self.openMultiServiceEPG))
pluginlist.append((_("Show EPG for current channel..."), self.openSingleServiceEPG))
return pluginlist
def showEventInfoPlugins(self):
if isMoviePlayerInfoBar(self):
self.openEventView()
else:
pluginlist = self.getEPGPluginList()
if pluginlist:
self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list=pluginlist, skin_name="EPGExtensionsList")
else:
self.openSingleServiceEPG()
def getDefaultGuidetype(self):
pluginlist = self.getEPGPluginList()
config.usage.defaultGuideType = ConfigSelection(default="None", choices=pluginlist)
for plugin in pluginlist:
if plugin[0] == config.usage.defaultGuideType.value:
return plugin[1]
return None
def showEventGuidePlugins(self):
if isMoviePlayerInfoBar(self):
self.openEventView()
else:
pluginlist = self.getEPGPluginList()
if pluginlist:
pluginlist.append((_("Select default EPG type..."), self.SelectDefaultGuidePlugin))
self.session.openWithCallback(self.EventGuidePluginChosen, ChoiceBox, title=_("Please choose an extension..."), list=pluginlist, skin_name="EPGExtensionsList")
else:
self.openSingleServiceEPG()
def SelectDefaultGuidePlugin(self):
self.session.openWithCallback(self.DefaultGuidePluginChosen, ChoiceBox, title=_("Please select a default EPG type..."), list=self.getEPGPluginList(), skin_name="EPGExtensionsList")
def DefaultGuidePluginChosen(self, answer):
if answer is not None:
self.defaultGuideType = answer[1]
config.usage.defaultGuideType.value = answer[0]
config.usage.defaultGuideType.save()
def EventGuidePluginChosen(self, answer):
if answer is not None:
answer[1]()
def runPlugin(self, plugin):
plugin(session=self.session, servicelist=self.servicelist)
def EventInfoPluginChosen(self, answer):
if answer is not None:
answer[1]()
def InfoPressed(self):
if isStandardInfoBar(self) or isMoviePlayerInfoBar(self):
if config.plisettings.PLIINFO_mode.value == "eventview":
self.openEventView()
elif config.plisettings.PLIINFO_mode.value == "epgpress":
self.EPGPressed()
elif config.plisettings.PLIINFO_mode.value == "single":
self.openSingleServiceEPG()
else:
if config.plisettings.PLIINFO_mode.value != "infobar":
self.EPGPressed()
def IPressed(self):
if isStandardInfoBar(self) or isMoviePlayerInfoBar(self):
self.openEventView()
def EPGPressed(self):
if isStandardInfoBar(self) or isMoviePlayerInfoBar(self):
if config.plisettings.PLIEPG_mode.value == "pliepg":
self.openGraphEPG()
elif config.plisettings.PLIEPG_mode.value == "multi":
self.openMultiServiceEPG()
elif config.plisettings.PLIEPG_mode.value == "single":
self.openSingleServiceEPG()
elif config.plisettings.PLIEPG_mode.value == "vertical":
self.openVerticalEPG()
# elif config.plisettings.PLIEPG_mode.value == "merlinepgcenter":
# self.openMerlinEPGCenter()
elif config.plisettings.PLIEPG_mode.value == "eventview":
self.openEventView()
else:
self.openSingleServiceEPG()
def showEventInfoWhenNotVisible(self):
if self.shown:
self.openEventView()
else:
self.toggleShow()
return 1
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.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 the service list.
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 servicelist is not 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 openBouquetEPG(self, bouquet=None, bouquets=None):
if bouquet:
self.StartBouquet = bouquet
self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, None, zapFunc=self.zapToService, EPGtype=self.EPGtype, StartBouquet=self.StartBouquet, StartRef=self.StartRef, bouquets=bouquets))
def closed(self, ret=False):
if not self.dlg_stack:
return
closedScreen = self.dlg_stack.pop()
if self.bouquetSel and closedScreen == self.bouquetSel:
self.bouquetSel = None
elif self.eventView and closedScreen == self.eventView:
self.eventView = None
if ret is True or ret == "close":
dlgs = len(self.dlg_stack)
if dlgs > 0:
self.dlg_stack[dlgs - 1].close(dlgs > 1)
self.reopen(ret)
def MultiServiceEPG(self):
bouquets = self.servicelist.getBouquetList()
if bouquets is None:
cnt = 0
else:
cnt = len(bouquets)
if (self.EPGtype == "multi" and config.epgselection.multi_showbouquet.value) or (self.EPGtype == "graph" and config.epgselection.graph_showbouquet.value):
if cnt > 1: # Show bouquet list.
self.bouquetSel = self.session.openWithCallback(self.closed, EpgBouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
self.dlg_stack.append(self.bouquetSel)
elif cnt == 1:
self.openBouquetEPG(bouquets=bouquets)
else:
self.openBouquetEPG(bouquets=bouquets)
def openMultiServiceEPG(self):
if self.servicelist is None:
return
self.EPGtype = "multi"
self.StartBouquet = self.servicelist.getRoot()
if isMoviePlayerInfoBar(self):
self.StartRef = self.lastservice
else:
self.StartRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
self.MultiServiceEPG()
def openGraphEPG(self, reopen=False):
if self.servicelist is None:
return
self.EPGtype = "graph"
if not reopen:
self.StartBouquet = self.servicelist.getRoot()
self.StartRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
self.MultiServiceEPG()
def openSingleServiceEPG(self, reopen=False):
if self.servicelist is None:
return
self.EPGtype = "enhanced"
self.SingleServiceEPG()
def openVerticalEPG(self, reopen=False):
if self.servicelist is None:
return
if not reopen:
self.StartBouquet = self.servicelist.getRoot()
self.StartRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
self.EPGtype = "vertical"
self.VerticalEPG()
def VerticalEPG(self):
# self.StartBouquet = self.servicelist.getRoot()
# self.StartRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
bouquets = self.servicelist.getBouquetList()
self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, self.servicelist, zapFunc=self.zapToService, EPGtype=self.EPGtype, StartBouquet=self.StartBouquet, StartRef=self.StartRef, bouquets=bouquets))
def openInfoBarEPG(self, reopen=False):
if self.servicelist is None:
return
if not reopen:
self.StartBouquet = self.servicelist.getRoot()
self.StartRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
if config.epgselection.infobar_type_mode.value == "single":
self.EPGtype = "infobar"
self.SingleServiceEPG()
else:
self.EPGtype = "infobargraph"
self.MultiServiceEPG()
def SingleServiceEPG(self):
self.StartBouquet = self.servicelist.getRoot()
self.StartRef = self.session.nav.getCurrentlyPlayingServiceOrGroup()
if isMoviePlayerInfoBar(self):
ref = self.lastservice
else:
ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
if ref:
services = self.getBouquetServices(self.StartBouquet)
self.serviceSel = SimpleServicelist(services)
if self.serviceSel.selectService(ref):
self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, self.servicelist, zapFunc=self.zapToService, serviceChangeCB=self.changeServiceCB, EPGtype=self.EPGtype, StartBouquet=self.StartBouquet, StartRef=self.StartRef)
else:
self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref)
def changeServiceCB(self, direction, epg):
if self.serviceSel:
if direction > 0:
self.serviceSel.nextService()
else:
self.serviceSel.prevService()
epg.setService(self.serviceSel.currentService())
def SingleServiceEPGClosed(self, ret=False):
self.serviceSel = None
self.reopen(ret)
def reopen(self, answer):
if answer == "reopengraph":
self.openGraphEPG(True)
elif answer == "reopenvertical":
self.openVerticalEPG(True)
elif answer == "reopeninfobargraph" or answer == "reopeninfobar":
self.openInfoBarEPG(True)
elif answer == "close" and isMoviePlayerInfoBar(self):
self.lastservice = self.session.nav.getCurrentlyPlayingServiceOrGroup()
self.close()
def openMerlinEPGCenter(self):
if self.servicelist is None:
return
if isPluginInstalled("MerlinEPGCenter"):
for plugin in plugins.getPlugins([PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_EVENTINFO]):
if plugin.name == _("Merlin EPG Center"):
self.runPlugin(plugin)
break
else:
self.session.open(MessageBox, _("The Merlin EPG Center plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10)
def openSimilarList(self, eventid, refstr):
self.session.open(EPGSelection, 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 and ptr.getEventName() != "":
epglist.append(ptr)
ptr = info and info.getEvent(1)
if ptr and ptr.getEventName() != "":
epglist.append(ptr)
self.epglist = epglist
def __evEventInfoChanged(self):
self.isInfo = True
if self.is_now_next and len(self.dlg_stack) == 1:
self.getNowNext()
if self.eventView and self.epglist:
self.eventView.setEvent(self.epglist[0])
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:
if not simple:
self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
else:
self.eventView = self.session.openWithCallback(self.closed, EventViewSimple, epglist[0], ServiceReference(ref))
self.dlg_stack.append(self.eventView)
def eventViewCallback(self, setEvent, setService, val): # Used for Now/Next display.
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, _("Start RDS interactive"))
}, prio=-1, description=_("InfoBar RDS Actions"))
self["RdsActions"].setEnabled(False)
self.onLayoutFinish.append(self.rds_display.show)
self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
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.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["time"] = Label()
self["actions"] = HelpableActionMap(self, ["WizardActions", "DirectionActions"], {
"back": (self.exit, _("Cancel selection")),
"ok": (self.keyOK, _("Seek forward long")),
"left": (self.keyLeft, _("Seek back short")),
"right": (self.keyRight, _("Seek forward short"))
}, prio=-1, description=_("Seek Actions"))
self.cursorTimer = eTimer()
self.cursorTimer.callback.append(self.updateCursor)
self.cursorTimer.start(200, False)
def updateCursor(self):
if self.length:
screenwidth = getDesktop(0).size().width()
if screenwidth and screenwidth == 1920:
x = 218 + int(4.05 * self.percent)
self["cursor"].moveTo(x, 23, 1)
else:
x = 145 + int(2.7 * self.percent)
self["cursor"].moveTo(x, 15, 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
def keyNumberGlobal(self, number):
sel = self["config"].getCurrent()[1]
if sel == self.positionEntry:
self.percent = float(number) * 10.0
else:
ConfigListScreen.keyNumberGlobal(self, number)
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
def action(self, contexts, action):
# print("action:", action)
if action[:5] == "seek:":
time = int(action[5:])
self.screen.doSeekRelative(time * 90000)
return 1
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]
self.screen.doSeekRelative(time * 90000)
return 1
else:
return HelpableActionMap.action(self, contexts, action)
self["SeekActions"] = InfoBarSeekActionMap(self, actionmap, {
"playpauseService": (self.playpauseService, _("Pause/Continue playback")),
"pauseService": (self.pauseService, _("Pause playback")),
"pauseServiceYellow": (self.pauseServiceYellow, _("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) # Give them a little more priority to win over the color buttons.
self["SeekActions"].setEnabled(False)
self["SeekActionsPTS"] = InfoBarSeekActionMap(self, "InfobarSeekActionsPTS", {
"playpauseService": self.playpauseService,
"pauseService": (self.pauseService, _("Pause playback")),
"pauseServiceYellow": (self.pauseServiceYellow, _("Pause playback")),
"unPauseService": (self.unPauseService, _("Continue playback")),
"seekFwd": (self.seekFwd, _("skip forward")),
"seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
"seekBack": (self.seekBack, _("skip backward")),
"seekBackManual": (self.seekBackManual, _("skip backward (enter time)")),
}, prio=-1) # Give them a little more priority to win over the 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.seekAction = 0
self.LastseekAction = False
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():
BoxInfo.setMutableItem("SeekStatePlay", False)
if exists("/proc/stb/lcd/symbol_hdd"):
f = open("/proc/stb/lcd/symbol_hdd", "w")
f.write("0")
f.close()
if exists("/proc/stb/lcd/symbol_hddprogress"):
f = open("/proc/stb/lcd/symbol_hddprogress", "w")
f.write("0")
f.close()
# 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(int(config.seek.withjumps_repeat_ms.getValue()), False)
for c in self.onPlayStateChanged:
c(self.seekstate)
global seek_withjumps_muted
if seek_withjumps_muted and eDVBVolumecontrol.getInstance().isMuted():
print("[InfoBarGenerics] STILL MUTED AFTER FFWD/FBACK !!!!!!!! so we unMute")
seek_withjumps_muted = False
eDVBVolumecontrol.getInstance().volumeUnMute()
def doActivityTimer(self):
if self.isSeekable():
self.activity += 16
hdd = 1
if self.activity >= 100:
self.activity = 0
BoxInfo.setMutableItem("SeekStatePlay", True)
if exists("/proc/stb/lcd/symbol_hdd"):
if config.lcd.hdd.value:
file = open("/proc/stb/lcd/symbol_hdd", "w")
file.write("%d" % int(hdd))
file.close()
if exists("/proc/stb/lcd/symbol_hddprogress"):
if config.lcd.hdd.value:
file = open("/proc/stb/lcd/symbol_hddprogress", "w")
file.write("%d" % int(self.activity))
file.close()
else:
self.activityTimer.stop()
self.activity = 0
hdd = 0
self.seekAction = 0
BoxInfo.setMutableItem("SeekStatePlay", True)
if exists("/proc/stb/lcd/symbol_hdd"):
if config.lcd.hdd.value:
file = open("/proc/stb/lcd/symbol_hdd", "w")
file.write("%d" % int(hdd))
file.close()
if exists("/proc/stb/lcd/symbol_hddprogress"):
if config.lcd.hdd.value:
file = open("/proc/stb/lcd/symbol_hddprogress", "w")
file.write("%d" % int(self.activity))
file.close()
if self.LastseekAction:
self.DoSeekAction()
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("not pauseable.")
state = self.SEEK_STATE_PLAY
self.seekstate = state
if pauseable is not None:
if self.seekstate[0] and self.seekstate[3] == "||":
# print("resolved to PAUSE")
self.activityTimer.stop()
pauseable.pause()
elif self.seekstate[0] and self.seekstate[3] == "END":
# print("resolved to STOP")
self.activityTimer.stop()
elif self.seekstate[1]:
if not pauseable.setFastForward(self.seekstate[1]):
pass
# print("resolved to FAST FORWARD")
else:
self.seekstate = self.SEEK_STATE_PLAY
# print("FAST FORWARD not possible: resolved to PLAY")
elif self.seekstate[2]:
if not pauseable.setSlowMotion(self.seekstate[2]):
pass
# print("resolved to SLOW MOTION")
else:
self.seekstate = self.SEEK_STATE_PAUSE
# print("SLOW MOTION not possible: resolved to PAUSE")
else:
# print("resolved to PLAY")
self.activityTimer.start(int(config.seek.withjumps_repeat_ms.getValue()), 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.seekAction != 0:
self.seekAction = 0
self.doPause(False)
global seek_withjumps_muted
seek_withjumps_muted = False
return
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):
BoxInfo.setMutableItem("StatePlayPause", True)
if self.seekstate != self.SEEK_STATE_EOF:
self.lastseekstate = self.seekstate
self.setSeekState(self.SEEK_STATE_PAUSE)
def pauseServiceYellow(self):
# if config.plugins.infopanel_yellowkey.list.value == "0":
self.audioSelection()
# elif config.plugins.infopanel_yellowkey.list.value == "2":
# ToggleVideo()
# else:
# self.playpauseService()
def unPauseService(self):
BoxInfo.setMutableItem("StatePlayPause", False)
if self.seekstate == self.SEEK_STATE_PLAY:
if self.seekAction != 0:
self.playpauseService()
# return 0 # If 'return 0', plays time shift again from the beginning.
return
self.doPause(False)
self.setSeekState(self.SEEK_STATE_PLAY)
if config.usage.show_infobar_on_skip.value and not config.usage.show_infobar_locked_on_pause.value:
self.showAfterSeek()
self.skipToggleShow = True # Skip 'break' action (toggleShow) after 'make' action (unPauseService).
def doPause(self, pause):
if pause:
if not eDVBVolumecontrol.getInstance().isMuted():
eDVBVolumecontrol.getInstance().volumeMute()
else:
if eDVBVolumecontrol.getInstance().isMuted():
eDVBVolumecontrol.getInstance().volumeUnMute()
def doSeek(self, pts):
seekable = self.getSeek()
if seekable is None:
return
seekable.seekTo(pts)
def doSeekRelativeAvoidStall(self, pts):
global jump_pts_adder
global jump_last_pts
global jump_last_pos
seekable = self.getSeek()
# When config.seek.withjumps, avoid that jumps smaller than the time between I-frames result in hanging, by increasing pts when stalled.
if seekable and config.seek.withjumps_avoid_zero.getValue():
position = seekable.getPlayPosition()
if jump_last_pos and jump_last_pts:
if (abs(position[1] - jump_last_pos[1]) < 100 * 90) and (pts == jump_last_pts): # Stalled?
jump_pts_adder += pts
jump_last_pts = pts
pts += jump_pts_adder
else:
jump_pts_adder = 0
jump_last_pts = pts
else:
jump_last_pts = pts
jump_last_pos = position
self.doSeekRelative(pts)
def doSeekRelative(self, pts):
try:
if "" in repr(self):
if InfoBarTimeshift.timeshiftEnabled(self):
length = InfoBarTimeshift.ptsGetLength(self)
position = InfoBarTimeshift.ptsGetPosition(self)
if length is None or position is None:
return
if position + pts >= length:
InfoBarTimeshift.evEOF(self, position + pts - length)
self.showAfterSeek()
return
elif position + pts < 0:
InfoBarTimeshift.evSOF(self, position + pts)
self.showAfterSeek()
return
except Exception:
from sys import exc_info
print("[InfoBarGenerics] error in 'def doSeekRelative'", exc_info()[:2])
seekable = self.getSeek()
if seekable is None or int(seekable.getLength()[1]) < 1:
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 or not config.usage.show_infobar_locked_on_pause.value) and config.usage.show_infobar_on_skip.value:
self.showAfterSeek()
def DoSeekAction(self):
if self.seekAction > int(config.seek.withjumps_after_ff_speed.getValue()):
self.doSeekRelativeAvoidStall(self.seekAction * int(config.seek.withjumps_forwards_ms.getValue()) * 90)
elif self.seekAction < 0:
self.doSeekRelativeAvoidStall(self.seekAction * int(config.seek.withjumps_backwards_ms.getValue()) * 90)
for c in self.onPlayStateChanged:
if self.seekAction > int(config.seek.withjumps_after_ff_speed.getValue()): # Forward.
c((0, self.seekAction, 0, ">> %dx" % self.seekAction))
elif self.seekAction < 0: # Backward.
c((0, self.seekAction, 0, "<< %dx" % abs(self.seekAction)))
if self.seekAction == 0:
self.LastseekAction = False
self.doPause(False)
global seek_withjumps_muted
seek_withjumps_muted = False
self.setSeekState(self.SEEK_STATE_PLAY)
def isServiceTypeTS(self):
ref = self.session.nav.getCurrentlyPlayingServiceReference()
isTS = False
if ref is not None:
servincetype = ServiceReference(ref).getType()
if servincetype == 1:
isTS = True
return isTS
def seekFwd(self):
if config.seek.withjumps.value and not self.isServiceTypeTS():
self.seekFwd_new()
else:
self.seekFwd_old()
def seekBack(self):
if config.seek.withjumps.value and not self.isServiceTypeTS():
self.seekBack_new()
else:
self.seekBack_old()
def seekFwd_new(self):
self.LastseekAction = True
self.doPause(True)
global seek_withjumps_muted
seek_withjumps_muted = True
if self.seekAction >= 0:
self.seekAction = self.getHigher(abs(self.seekAction), config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
else:
self.seekAction = -self.getLower(abs(self.seekAction), config.seek.speeds_backward.value)
if (self.seekAction > 1) and (self.seekAction <= int(config.seek.withjumps_after_ff_speed.getValue())): # Use fast forward for the configured speeds.
self.setSeekState(self.makeStateForward(self.seekAction))
elif self.seekAction > int(config.seek.withjumps_after_ff_speed.getValue()): # We first need to go the play state, to stop fast forward.
self.setSeekState(self.SEEK_STATE_PLAY)
def seekBack_new(self):
self.LastseekAction = True
self.doPause(True)
global seek_withjumps_muted
seek_withjumps_muted = True
if self.seekAction <= 0:
self.seekAction = -self.getHigher(abs(self.seekAction), config.seek.speeds_backward.value) or -config.seek.speeds_backward.value[-1]
else:
self.seekAction = self.getLower(abs(self.seekAction), config.seek.speeds_forward.value)
if (self.seekAction > 1) and (self.seekAction <= int(config.seek.withjumps_after_ff_speed.getValue())): # Use fast forward for the configured forwards speeds.
self.setSeekState(self.makeStateForward(self.seekAction))
def seekFwd_old(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)
self.fast_winding_hint_message_showed = True
return
return 0 # Treat 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_old(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)
self.fast_winding_hint_message_showed = True
return
return 0 # Treat 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 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 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()
elif self.seekstate == self.SEEK_STATE_PAUSE and not config.usage.show_infobar_locked_on_pause.value:
if config.usage.show_infobar_on_skip.value:
self.lockedBecauseOfSkipping = False
self.unlockShow()
self.showAfterSeek()
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 Exception:
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
global seek_withjumps_muted
if seek_withjumps_muted and eDVBVolumecontrol.getInstance().isMuted():
print("[InfoBarGenerics] STILL MUTED AFTER FFWD/FBACK !!!!!!!! so we unMute")
seek_withjumps_muted = False
eDVBVolumecontrol.getInstance().volumeUnMute()
# 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
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.DimmingTimer.stop()
self.doWriteAlpha(config.av.osd_alpha.value)
self.pvrStateDialog.show()
self.startHideTimer()
def __playStateChanged(self, state):
playstateString = state[3]
state_summary = playstateString
if "statusicon" in self.pvrStateDialog:
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():
InfoBarTimeshift.ptsSeekPointerSetCurrentPos(self)
if config.timeshift.showInfoBar.value:
self["TimeshiftSeekPointerActions"].setEnabled(True)
self.pvrStateDialog.show()
if not self.isSeekable():
self.startHideTimer()
def __hideTimeshiftState(self):
self["TimeshiftSeekPointerActions"].setEnabled(False)
self.pvrStateDialog.hide()
def __timeshiftEventName(self, state):
if self.timeshiftEnabled() and exists("%spts_livebuffer_%s.meta" % (config.timeshift.path.value, self.pts_currplaying)):
readmetafile = open("%spts_livebuffer_%s.meta" % (config.timeshift.path.value, self.pts_currplaying))
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"))
}, prio=0, description=_("Movie List Actions"))
class InfoBarExtensions:
EXTENSION_SINGLE = 0
EXTENSION_LIST = 1
def __init__(self):
self.list = []
if config.plisettings.ColouredButtons.value:
self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions", {
"extensions": (self.bluekey_ex, _("Show extensions...")),
"quickmenu": (self.bluekey_qm, _("Show quickmenu...")),
"showPluginBrowser": (self.showPluginBrowser, _("Show the plugin browser..")),
"showEventInfo": (self.SelectopenEventView, _("Show the information on current event.")),
"openTimerList": (self.showTimerList, _("Show the list of timers.")),
"openAutoTimerList": (self.showAutoTimerList, _("Show the list of AutoTimers.")),
"openEPGSearch": (self.showEPGSearch, _("Search the epg for current event.")),
"openIMDB": (self.showIMDB, _("Search IMDb for information about current event.")),
"showMediaPlayer": (self.showMediaPlayer, _("Show the media player...")),
"openDreamPlex": (self.showDreamPlex, _("Show the DreamPlex player...")),
}, prio=1, description=_("Extension Actions")) # Lower priority.
else:
self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions", {
"extensions": (self.bluekey_ex, _("view extensions...")),
"quickmenu": (self.bluekey_qm, _("Show quickmenu...")),
"showPluginBrowser": (self.showPluginBrowser, _("Show the plugin browser..")),
"showDreamPlex": (self.showDreamPlex, _("Show the DreamPlex player...")),
"showEventInfo": (self.SelectopenEventView, _("Show the information on current event.")),
"showMediaPlayer": (self.showMediaPlayer, _("Show the media player...")),
}, prio=1, description=_("Extension Actions")) # Lower priority.
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)
self.addExtension(extension=self.getSoftcamSetup, type=InfoBarExtensions.EXTENSION_LIST)
if config.usage.show_restart_network_extensionslist.getValue() is True:
self.addExtension(extension=self.getRestartNetwork, type=InfoBarExtensions.EXTENSION_LIST)
for p in plugins.getPlugins(PluginDescriptor.WHERE_EXTENSIONSINGLE):
p(self)
def bluekey_qm(self):
if config.workaround.blueswitch.value:
self.showExtensionSelection()
else:
self.quickmenuStart()
def bluekey_ex(self):
if config.workaround.blueswitch.value:
self.quickmenuStart()
else:
self.showExtensionSelection()
def quickmenuStart(self):
try:
if self.session.pipshown:
self.showExtensionSelection()
return
except Exception:
print("[INFOBARGENERICS] QuickMenu: error pipshow, starting Quick Menu")
from Screens.QuickMenu import QuickMenu
self.session.open(QuickMenu)
def SelectopenEventView(self):
try:
self.openEventView()
except Exception:
pass
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 getSoftcamSetupname(self):
return _("Softcam Settings")
def getSoftcamSetup(self):
return [((boundFunction(self.getSoftcamSetupname), boundFunction(self.openSoftcamSetup), lambda: True), None)] if BoxInfo.getItem("SoftCam") else []
def getRestartNetworkname(self):
return _("Restart Network")
def getRestartNetwork(self):
return [((boundFunction(self.getRestartNetworkname), boundFunction(self.openRestartNetwork), lambda: True), None)]
def get3DSetupname(self):
return _("OSD 3D Settings")
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):
if pathExists("/usr/bin/"):
softcams = listdir("/usr/bin/")
for softcam in softcams:
if softcam.lower().startswith("cccam") and config.softcam.showInExtensions.value:
return [((boundFunction(self.getCCname), boundFunction(self.openCCcamInfo), lambda: True), None)] or []
else:
return []
def getOSname(self):
return _("OSCam Info")
def getOScamInfo(self):
if pathExists("/usr/bin/"):
softcams = listdir("/usr/bin/")
for softcam in softcams:
if softcam.lower().startswith("oscam") and config.softcam.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))
if config.usage.sort_extensionslist.value:
print("[InfoBarExtensions] sort_extensionslist not supported yet")
# FIME: Sort extensions.
# self.list.sort()
def updateExtension(self, extension, key=None):
self.extensionsList.append(extension)
if key is not None:
if 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 = []
colorlist = []
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]())
if self.availableKeys.index(x) < 10:
list.append((extension[0](), extension))
else:
colorlist.append((extension[0](), extension))
keys.append(x)
extensionsList.remove(extension)
else:
extensionsList.remove(extension)
if config.usage.sort_extensionslist.value:
print("[InfoBarExtensions] sort_extensionslist not supported yet")
# FIME: Sort extensions.
# list.sort()
for x in colorlist:
list.append(x)
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")
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 OSCamInfo
self.session.open(OSCamInfo)
def showTimerList(self):
self.session.open(RecordTimerOverview)
def openLogManager(self):
from Screens.LogManager import LogManager
self.session.open(LogManager)
def open3DSetup(self):
from Screens.Setup import Setup
self.session.open(Setup, "OSD3D")
def openSoftcamSetup(self):
from Screens.SoftcamSetup import SoftcamSetup
self.session.open(SoftcamSetup)
def openRestartNetwork(self):
try:
from Screens.RestartNetwork import RestartNetwork
self.session.open(RestartNetwork)
except Exception:
print("[INFOBARGENERICS] failed to restart network")
def showAutoTimerList(self):
if isPluginInstalled("AutoTimer"):
from Plugins.Extensions.AutoTimer.plugin import main, autostart
from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
from Plugins.Extensions.AutoTimer.AutoPoller import AutoPoller
self.autopoller = AutoPoller()
self.autotimer = AutoTimer()
try:
self.autotimer.readXml()
except SyntaxError as se:
self.session.open(
MessageBox,
_("Your config file is not well-formed:\n%s") % (str(se)),
type=MessageBox.TYPE_ERROR,
timeout=10
)
return
# Do not run in background while editing, this might screw things up.
if self.autopoller is not None:
self.autopoller.stop()
from Plugins.Extensions.AutoTimer.AutoTimerOverview import AutoTimerOverview
self.session.openWithCallback(
self.editCallback,
AutoTimerOverview,
self.autotimer
)
else:
self.session.open(MessageBox, _("The AutoTimer plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10)
def editCallback(self, session):
# XXX: Canceling of GUI (Overview) won't affect config values which might have been changed - is this intended?
# Don't parse EPG if editing was canceled.
if session is not None:
self.autotimer.writeXml() # Save XML.
self.autotimer.parseEPG() # Poll EPGCache.
if config.plugins.autotimer.autopoll.value: # Start autopoller again if wanted.
if self.autopoller is None:
from Plugins.Extensions.AutoTimer.AutoPoller import AutoPoller
self.autopoller = AutoPoller()
self.autopoller.start()
else: # Remove instance if not running in background.
self.autopoller = None
self.autotimer = None
def showEPGSearch(self):
from Plugins.Extensions.EPGSearch.EPGSearch import EPGSearch
s = self.session.nav.getCurrentService()
if s:
info = s.info()
event = info.getEvent(0) # 0 = Now, 1 = Next.
if event:
name = 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):
if isPluginInstalled("IMDb"):
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)
else:
self.session.open(MessageBox, _("The IMDb plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10)
def showMediaPlayer(self):
if isinstance(self, InfoBarExtensions):
if isinstance(self, InfoBar):
try: # If it is not installed.
from Plugins.Extensions.MediaPlayer.plugin import MediaPlayer
self.session.open(MediaPlayer)
no_plugin = False
except Exception as e:
self.session.open(MessageBox, _("The MediaPlayer plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10)
def showDreamPlex(self):
if isPluginInstalled("DreamPlex"):
from Plugins.Extensions.DreamPlex.plugin import DPS_MainMenu
self.session.open(DPS_MainMenu)
else:
self.session.open(MessageBox, _("The DreamPlex plugin is not installed!\nPlease install it."), type=MessageBox.TYPE_INFO, timeout=10)
# 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 = getfullargspec(p.__call__)[0] # FIME: This is a performance issue and should be replaced.
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:
try:
plugin(session=self.session)
except Exception as err:
print("[InfoBarGenerics] Error: ", err)
class InfoBarJobman:
def __init__(self):
self.addExtension(extension=self.getJobList, type=InfoBarExtensions.EXTENSION_LIST)
def getJobList(self):
return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()] if config.usage.jobtaksextensions.value else []
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 Exception:
self.session.pipshown = False
self.lastPiPService = None
if BoxInfo.getItem("PIPAvailable") and isinstance(self, InfoBarEPG):
self["PiPActions"] = HelpableActionMap(self, "InfobarPiPActions", {
"activatePiP": (self.activePiP, self.activePiPName),
}, prio=0, description=_("PiP Actions"))
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.lastPiPServiceTimeoutTimer = eTimer()
self.lastPiPServiceTimeoutTimer.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):
return _("Disable Picture in Picture") if self.session.pipshown else _("Activate Picture in Picture")
def getSwapName(self):
return _("Swap services")
def getMoveName(self):
return _("Picture in Picture Setup")
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):
self.lastPiPServiceTimeoutTimer.stop()
slist = self.servicelist
if self.session.pipshown:
if slist and slist.dopipzap:
self.togglePipzap()
if self.session.pipshown:
lastPiPServiceTimeout = int(config.usage.pip_last_service_timeout.value)
if lastPiPServiceTimeout >= 0:
self.lastPiPService = self.session.pip.getCurrentServiceReference()
if lastPiPServiceTimeout:
self.lastPiPServiceTimeoutTimer.startLongTimer(lastPiPServiceTimeout)
del self.session.pip
if BoxInfo.getItem("LCDMiniTV") and config.lcd.modepip.value >= 1:
print("[InfoBarGenerics] [LCDMiniTV] disable PiP")
eDBoxLCD.getInstance().setLCDMode(config.lcd.modeminitv.value)
self.session.pipshown = False
if hasattr(self, "ScreenSaverTimerStart"):
self.ScreenSaverTimerStart()
else:
service = self.session.nav.getCurrentService()
info = service and service.info()
if info:
xres = str(info.getInfo(iServiceInformation.sVideoWidth))
if info and int(xres) <= 720 or BoxInfo.getItem("model") != "blackbox7405":
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 BoxInfo.getItem("LCDMiniTVPiP") and config.lcd.modepip.value >= 1:
print("[InfoBarGenerics] [LCDMiniTV] enable PiP")
eDBoxLCD.getInstance().setLCDMode(config.lcd.modepip.value, True)
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 BoxInfo.getItem("LCDMiniTVPiP") and config.lcd.modepip.value >= 1:
print("[InfoBarGenerics] [LCDMiniTV] enable PiP")
eDBoxLCD.getInstance().setLCDMode(config.lcd.modepip.value, True)
else:
self.lastPiPService = None
self.session.pipshown = False
del self.session.pip
elif info:
self.session.open(MessageBox, _("Your %s %s does not support PiP HD") % getBoxDisplayName(), type=MessageBox.TYPE_INFO, timeout=5)
else:
self.session.open(MessageBox, _("No active channel found."), type=MessageBox.TYPE_INFO, timeout=5)
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.stopService() # Stop portal.
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 InfoBarQuickMenu:
def __init__(self):
self["QuickMenuActions"] = HelpableActionMap(self, "InfoBarQuickMenu", {
"quickmenu": (self.bluekey_qm, _("Quick Menu...")),
}, prio=0, description=_("QuickMenu Actions"))
def bluekey_qm(self):
if config.workaround.blueswitch.value:
self.showExtensionSelection()
else:
self.quickmenuStart()
def quickmenuStart(self):
try:
if self.session.pipshown:
self.showExtensionSelection()
return
except Exception:
print("[INFOBARGENERICS] QuickMenu: error pipshow, starting Quick Menu")
from Screens.QuickMenu import QuickMenu
self.session.open(QuickMenu)
class InfoBarInstantRecord:
"""Instant Record - Handles the instantRecord action in order to start/stop instant recordings."""
def __init__(self):
self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord", {
"instantRecord": (self.instantRecord, _("Start an instant recording")),
}, prio=0, description=_("Instant Recording Actions"))
self.SelectedInstantServiceRef = None
if isStandardInfoBar(self):
self.recording = []
else:
from Screens.InfoBar import InfoBar
InfoBarInstance = InfoBar.instance
if InfoBarInstance:
self.recording = InfoBarInstance.recording
self.saveTimeshiftEventPopupActive = False
def stopCurrentRecording(self, entry=-1):
if entry is not None and entry != -1:
self.session.nav.RecordTimer.removeEntry(self.recording[entry])
self.recording.remove(self.recording[entry])
def getProgramInfoAndEvent(self, info, name):
info["serviceref"] = hasattr(self, "SelectedInstantServiceRef") and self.SelectedInstantServiceRef or self.session.nav.getCurrentlyPlayingServiceOrGroup()
# Try to get event information.
event = None
try:
epg = eEPGCache.getInstance()
event = epg.lookupEventTime(info["serviceref"], -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:
service = self.session.nav.getCurrentService()
event = service and service.info().getEvent(0)
except Exception:
pass
info["event"] = event
info["name"] = name
info["description"] = ""
info["eventid"] = None
if event is not None:
curEvent = parseEvent(event)
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 information found, recording default is 24 hours."), MessageBox.TYPE_INFO)
if isinstance(serviceref, eServiceReference):
serviceref = ServiceReference(serviceref)
if not limitEvent:
end = begin + (60 * 60 * 24) # 24 hours.
recording = RecordTimerEntry(serviceref, begin, end, info["name"], info["description"], info["eventid"], afterEvent=AFTEREVENT.AUTO, justplay=False, always_zap=False, dirname=preferredInstantRecordPath())
recording.marginBefore = 0
recording.dontSave = True
recording.eventBegin = recording.begin
if not limitEvent:
recording.marginAfter = 0
recording.eventEnd = recording.end
if event is None or limitEvent is 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(f"[InfoBarGenerics] InstantTimer 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") % f"\n\t'{name_date}'", MessageBox.TYPE_INFO)
else:
self.session.open(MessageBox, _("Could not record due to conflicting timer:%s") % f"\n\t'{name}'", MessageBox.TYPE_INFO)
else:
self.session.open(MessageBox, _("Could not record due to invalid service:%s") % f"\n\t'{serviceref}'", MessageBox.TYPE_INFO)
recording.autoincrease = False
def startRecordingCurrentEvent(self):
self.startInstantRecording(True)
def isInstantRecordRunning(self):
# print("[InfoBarGenerics] self.recording: {self.recording}")
if self.recording:
for x in self.recording:
if x.isRunning():
return True
return False
def recordQuestionCallback(self, answer):
# print("[InfoBarGenerics] recordQuestionCallback")
# print("[InfoBarGenerics] pre: {self.recording}")
if answer is None or answer[1] == "no":
self.saveTimeshiftEventPopupActive = False
return
items = []
recording = self.recording[:]
for x in recording:
if x not in self.session.nav.RecordTimer.timer_list:
self.recording.remove(x)
elif x.dontSave and x.isRunning():
items.append((x, False))
if answer[1] == "changeduration":
if len(self.recording) == 1:
self.changeDuration(0)
else:
self.session.openWithCallback(self.changeDuration, TimerSelection, items)
elif answer[1] == "changeendtime":
if len(self.recording) == 1:
self.changeEndtime(0)
else:
self.session.openWithCallback(self.changeEndtime, TimerSelection, items)
elif answer[1] == "timer":
self.session.open(RecordTimerOverview)
elif answer[1] == "stop":
self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, items)
elif answer[1] in ("indefinitely", "manualduration", "manualendtime", "event"):
if len(items) >= 2 and BoxInfo.getItem("ChipsetString") in ("meson-6", "meson-64"):
Notifications.AddNotification(MessageBox, _("Sorry it is only possible to record 2 channels at once!"), MessageBox.TYPE_ERROR, timeout=5)
return
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.changeEndtime(len(self.recording) - 1)
elif answer[1] == "savetimeshift":
if self.isSeekable() and self.pts_eventcount != self.pts_currplaying:
InfoBarTimeshift.SaveTimeshift(self, timeshiftfile="pts_livebuffer_%s" % self.pts_currplaying)
else:
Notifications.AddNotification(MessageBox, _("Time shift will get saved at end of event."), MessageBox.TYPE_INFO, timeout=5)
self.save_current_timeshift = True
config.timeshift.isRecording.value = True
elif answer[1] == "savetimeshiftEvent":
InfoBarTimeshift.saveTimeshiftEventPopup(self)
elif answer[1].startswith("pts_livebuffer") is True:
InfoBarTimeshift.SaveTimeshift(self, timeshiftfile=answer[1])
if answer[1] != "savetimeshiftEvent":
self.saveTimeshiftEventPopupActive = False
def changeEndtime(self, entry):
def changeEndtimeCallback(result):
if len(result) > 1 and result[0]:
print(f"[InfoBarGenerics] Instant recording due to stop at {strftime('%F %T', localtime(result[1]))}.")
if recordingEntry.end != result[1]:
recordingEntry.autoincrease = False
recordingEntry.end = result[1]
recordingEntry.eventEnd = recordingEntry.end
recordingEntry.marginAfter = 0 # Why is this being done?
self.session.nav.RecordTimer.timeChanged(recordingEntry)
if entry is not None and entry >= 0:
recordingEntry = self.recording[entry]
self.session.openWithCallback(changeEndtimeCallback, InstantRecordingEndTime, recordingEntry.eventEnd)
def changeDuration(self, entry):
def changeDurationCallback(value):
entry = self.recording[self.selectedEntry]
if value is not None:
value = int(value.replace(" ", "") or "0")
if value:
entry.autoincrease = False
print(f"[InfoBarGenerics] Instant recording due to stop after {value} minutes.")
entry.end = int(time()) + 60 * value
entry.eventEnd = entry.end
entry.marginAfter = 0
self.session.nav.RecordTimer.timeChanged(entry)
if entry is not None and entry >= 0:
self.selectedEntry = entry
self.session.openWithCallback(changeDurationCallback, InputBox, title=_("For how many minutes do you want to record?"), text="5 ", maxSize=True, type=Input.NUMBER)
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, "%s\n\n%s" % (_("Path '%s' missing!") % pirr, _("No HDD found or HDD not initialized!")), MessageBox.TYPE_ERROR)
return
if isStandardInfoBar(self):
commonRecord = [
(_("Add recording (Stop after current event)"), "event"),
(_("Add recording (Indefinitely - 24 hours)"), "indefinitely"),
(_("Add recording (Enter recording duration)"), "manualduration"),
(_("Add recording (Enter recording end time)"), "manualendtime")
]
commonTimeshift = [
(_("Time shift save recording (Stop after current event)"), "savetimeshift"),
(_("Time shift save recording (Select event)"), "savetimeshiftEvent")
]
else:
commonRecord = []
commonTimeshift = []
if self.isInstantRecordRunning():
title = _("A recording is currently running.\nWhat do you want to do?")
choiceList = [
(_("Stop recording"), "stop")
] + commonRecord + [
(_("Change recording (Duration)"), "changeduration"),
(_("Change recording (End time)"), "changeendtime")
]
if self.isTimerRecordRunning():
choiceList.append((_("Stop timer recording"), "timer"))
else:
title = _("Start instant recording?")
choiceList = commonRecord
if self.isTimerRecordRunning():
choiceList.append((_("Stop timer recording"), "timer"))
if isStandardInfoBar(self) and self.timeshiftEnabled():
choiceList.extend(commonTimeshift)
if isStandardInfoBar(self):
choiceList.append((_("Do not record"), "no"))
if choiceList:
self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=title, list=choiceList)
class InfoBarAudioSelection:
def __init__(self):
self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", {
"audioSelection": (self.audioSelection, _("Audio options...")),
"yellow_key": (self.yellow_key, _("Audio options...")),
"audioSelectionLong": (self.audioDownmixToggle, _("Toggle Digital downmix...")),
}, prio=0, description=_("Audio Actions"))
def yellow_key(self):
from Screens.AudioSelection import AudioSelection
self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
# if not hasattr(self, "LongButtonPressed"):
# self.LongButtonPressed = False
# global AUDIO
# if not self.LongButtonPressed:
# if config.plugins.infopanel_yellowkey.list.value == "0":
# from Screens.AudioSelection import AudioSelection
# self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
# elif config.plugins.infopanel_yellowkey.list.value == "2":
# AUDIO = True
# ToggleVideo()
# elif config.plugins.infopanel_yellowkey.list.value == "3":
# self.startTeletext()
# else:
# try:
# self.startTimeshift()
# except Exception:
# pass
# else:
# if config.plugins.infopanel_yellowkey.listLong.value == "0":
# from Screens.AudioSelection import AudioSelection
# self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
# elif config.plugins.infopanel_yellowkey.listLong.value == "2":
# AUDIO = True
# ToggleVideo()
# elif config.plugins.infopanel_yellowkey.listLong.value == "3":
# self.startTeletext()
# else:
# try:
# self.startTimeshift()
# except Exception:
# pass
def audioSelection(self):
from Screens.AudioSelection import AudioSelection
self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
def audioSelected(self, ret=None):
print("[InfoBarGenerics] [infobar::audioSelected]", ret)
def audioDownmixToggle(self, popup=True):
if BoxInfo.getItem("CanDownmixAC3"):
if config.av.downmix_ac3.value:
message = _("Dolby Digital downmix is now") + " " + _("disabled")
print("[InfoBarGenerics] [Audio] Dolby Digital downmix is now disabled")
config.av.downmix_ac3.setValue(False)
else:
config.av.downmix_ac3.setValue(True)
message = _("Dolby Digital downmix is now") + " " + _("enabled")
print("[InfoBarGenerics] [Audio] Dolby Digital downmix is now enabled")
if popup:
Notifications.AddPopup(text=message, type=MessageBox.TYPE_INFO, timeout=5, id="DDdownmixToggle")
def audioDownmixOn(self):
if not config.av.downmix_ac3.value:
self.audioDownmixToggle(False)
def audioDownmixOff(self):
if config.av.downmix_ac3.value:
self.audioDownmixToggle(False)
# Subservice processing.
#
instanceInfoBarSubserviceSelection = None
class InfoBarSubserviceSelection:
def __init__(self):
global instanceInfoBarSubserviceSelection
instanceInfoBarSubserviceSelection = self
self.subservicesGroups = self.loadSubservicesGroups()
self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions", {
"selectSubservices": (self.keySelectSubservice, _("Select subservices"))
}, prio=0, description=_("Subservice Actions"))
def loadSubservicesGroups(self):
subservicesGroups = []
groupedServicesFile = resolveFilename(SCOPE_CONFIG, "groupedservices")
if not isfile(groupedServicesFile):
groupedServicesFile = resolveFilename(SCOPE_SKINS, "groupedservices")
if not isfile(groupedServicesFile):
groupedServicesFile = None
print("[InfoBarGenerics] No 'groupedservices' file found so no subservices are available.")
if groupedServicesFile:
subservicesGroups = [list(g) for k, g in groupby([line.split("#")[0].strip() for line in fileReadLines(groupedServicesFile, [], source=MODULE_NAME)], lambda x: not x) if not k]
count = len(subservicesGroups)
print(f"[InfoBarGenerics] {count} subservice group{'' if count == 1 else 's'} loaded from '{groupedServicesFile}'.")
return subservicesGroups
def getSubserviceGroups(self):
return self.subservicesGroups
def hasActiveSubservicesForCurrentService(self, serviceReference):
if serviceReference and "%3a" not in serviceReference:
serviceReference = ":".join(serviceReference.split(":")[:11])
if config.usage.showInfoBarSubservices.value == 1:
subservices = self.getActiveSubservicesForCurrentService(serviceReference)
elif config.usage.showInfoBarSubservices.value == 2:
subservices = self.getPossibleSubservicesForCurrentService(serviceReference)
else:
subservices = None
return bool(subservices and len(subservices) > 1)
def getActiveSubservicesForCurrentService(self, serviceReference):
transmissionPaused = [
"Sendepause" # This is for German TV.
]
activeSubservices = []
if config.usage.showInfoBarSubservices.value and serviceReference:
possibleSubservices = self.getPossibleSubservicesForCurrentService(serviceReference)
epgCache = eEPGCache.getInstance()
for subservice in possibleSubservices:
events = epgCache.lookupEvent(["T", (subservice, 0, -1)])
if events and len(events) == 1:
title = events[0][0]
if title and not any([x for x in transmissionPaused if x in title]):
activeSubservices.append(subservice)
elif config.usage.showInfoBarSubservices.value == 2:
activeSubservices.append(subservice)
return activeSubservices
def getPossibleSubservicesForCurrentService(self, serviceReference):
possibleSubservices = []
if serviceReference and self.subservicesGroups:
possibleSubserviceGroups = [x for x in self.subservicesGroups if serviceReference in x]
if possibleSubserviceGroups:
possibleSubservices = possibleSubserviceGroups[0] # If the service is in multiple groups should we return more options?
return possibleSubservices
def keySelectSubservice(self):
noSubservice = True
if config.usage.subservice.value > 1:
serviceReference = self.session.nav.getCurrentlyPlayingServiceReference() and self.session.nav.getCurrentlyPlayingServiceReference().toCompareString()
if serviceReference:
if "%3a" in serviceReference:
serviceReference = self.session.nav.getCurrentlyPlayingServiceReference().toString()
subservices = self.getActiveSubservicesForCurrentService(serviceReference)
if subservices and len(subservices) > 1 and serviceReference in subservices:
self.servicelist.enterSubservices()
self.session.execDialog(self.servicelist)
noSubservice = False
if noSubservice:
if config.usage.subservice.value in (0, 2):
self.session.open(RecordTimerOverview)
else:
from Screens.PluginBrowser import PluginBrowser
self.session.open(PluginBrowser)
from Components.Sources.HbbtvApplication import HbbtvApplication
gHbbtvApplication = HbbtvApplication()
class InfoBarRedButton:
def __init__(self):
self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions", {
"activateRedButton": (self.activateRedButton, _("Red button...")),
}, prio=0, description=_("Red/HbbTV Button Actions"))
self["HbbtvApplication"] = gHbbtvApplication
self.onHBBTVActivation = []
self.onRedButtonActivation = []
self.onReadyForAIT = []
self.__et = ServiceEventTracker(screen=self, eventmap={
iPlayableService.evHBBTVInfo: self.detectedHbbtvApplication,
iPlayableService.evUpdatedInfo: self.updateInfomation
})
def updateAIT(self, orgId=0):
for x in self.onReadyForAIT:
try:
x(orgId)
except Exception as ErrMsg:
print("[InfoBarGenerics] updateAIT error", ErrMsg)
# self.onReadyForAIT.remove(x)
def updateInfomation(self):
try:
self["HbbtvApplication"].setApplicationName("")
self.updateAIT()
except Exception as ErrMsg:
pass
def detectedHbbtvApplication(self):
service = self.session.nav.getCurrentService()
info = service and service.info()
try:
for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
print("[InfoBarGenerics] HbbtvApplication:", x)
if x[0] in (-1, 1):
self.updateAIT(x[3])
self["HbbtvApplication"].setApplicationName(x[1])
break
except Exception as ErrMsg:
pass
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()
# TODO: Other red button services.
# elif False:
# for x in self.onRedButtonActivation:
# x()
class InfoBarTimerButton:
def __init__(self):
self["TimerButtonActions"] = HelpableActionMap(self, "InfobarTimerButtonActions", {
"timerSelection": (self.timerSelection, _("Timer selection...")),
}, prio=0, description=_("Timer Actions"))
def timerSelection(self):
self.session.open(RecordTimerOverview)
class InfoBarAspectSelection:
STATE_HIDDEN = 0
STATE_ASPECT = 1
STATE_RESOLUTION = 2
def __init__(self):
self["AspectSelectionAction"] = HelpableActionMap(self, "InfobarAspectSelectionActions", {
"aspectSelection": (self.ExGreen_toggleGreen, _("Aspect list...")),
}, prio=0, description=_("Aspect Ratio Actions"))
self.__ExGreen_state = self.STATE_HIDDEN
def ExGreen_doAspect(self):
print("[InfoBarGenerics] do self.STATE_ASPECT")
self.__ExGreen_state = self.STATE_ASPECT
self.aspectSelection()
def ExGreen_doResolution(self):
print("[InfoBarGenerics] do self.STATE_RESOLUTION")
self.__ExGreen_state = self.STATE_RESOLUTION
self.resolutionSelection()
def ExGreen_doHide(self):
print("[InfoBarGenerics] do self.STATE_HIDDEN")
self.__ExGreen_state = self.STATE_HIDDEN
def ExGreen_toggleGreen(self, arg=""):
print("[InfoBarGenerics] toggleGreen:", self.__ExGreen_state)
if self.__ExGreen_state == self.STATE_HIDDEN:
print("[InfoBarGenerics] self.STATE_HIDDEN")
self.ExGreen_doAspect()
elif self.__ExGreen_state == self.STATE_ASPECT:
print("[InfoBarGenerics] self.STATE_ASPECT")
self.ExGreen_doResolution()
elif self.__ExGreen_state == self.STATE_RESOLUTION:
print("[InfoBarGenerics] self.STATE_RESOLUTION")
self.ExGreen_doHide()
def aspectSelection(self):
selection = 0
if BoxInfo.getItem("AmlogicFamily"):
aspectList = [
(_("Resolution"), "resolution"),
("--", ""),
(_("Normal"), "0"),
(_("Full Stretch"), "1"),
("4:3", "2"),
("16:9", "3"),
(_("Non-Linear"), "4"),
(_("Normal No ScaleUp"), "5"),
(_("4:3 Ignore"), "6"),
(_("4:3 Letterbox"), "7"),
(_("4:3 PanScan"), "8"),
(_("4:3 Combined"), "9"),
(_("16:9 Ignore"), "10"),
(_("16:9 Letterbox"), "11"),
(_("16:9 PanScan"), "12"),
(_("16:9 Combined"), "13")
]
else:
aspectSwitchList = []
if config.av.aspectswitch.enabled.value:
for aspect in range(5):
aspectSwitchList.append((iAVSwitch.ASPECT_SWITCH_MSG[aspect], str(aspect + 100)))
aspectSwitchList.append(("--", ""))
aspectList = [
(_("Resolution"), "resolution"),
("--", "")
] + aspectSwitchList + [
(_("4:3 Letterbox"), "0"),
(_("4:3 PanScan"), "1"),
(_("16:9"), "2"),
(_("16:9 Always"), "3"),
(_("16:10 Letterbox"), "4"),
(_("16:10 PanScan"), "5"),
(_("16:9 Letterbox"), "6")
]
keys = ["green", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
aspect = iAVSwitch.getAspectRatioSetting()
selection = 0
for item in range(len(aspectList)):
if aspectList[item][1] == aspect:
selection = item
break
self.session.openWithCallback(self.aspectSelected, ChoiceBox, text=_("Please select an aspect ratio..."), list=aspectList, keys=keys, selection=selection)
def aspectSelected(self, aspect):
if aspect is not None:
if isinstance(aspect[1], str):
if aspect[1] == "":
self.ExGreen_doHide()
elif aspect[1] == "resolution":
self.ExGreen_toggleGreen()
else:
iAVSwitch.setAspectRatio(int(aspect[1]))
self.ExGreen_doHide()
else:
self.ExGreen_doHide()
class InfoBarResolutionSelection:
def __init__(self):
pass
def resolutionSelection(self):
avControl = eAVControl.getInstance()
fps = float(avControl.getFrameRate(50000)) / 1000.0
yRes = avControl.getResolutionY(0)
xRes = avControl.getResolutionX(0)
resList = []
resList.append((_("Exit"), "exit"))
resList.append((_("Auto(not available)"), "auto"))
resList.append((_("Video: ") + "%dx%d@%gHz" % (xRes, yRes, fps), ""))
resList.append(("--", ""))
# Do we need a new sorting with this way here or should we disable some choices?
videoModes = iAVSwitch.readPreferredModes(readOnly=True)
videoModes = [x.replace("pal ", "").replace("ntsc ", "") for x in videoModes] # Do we need this?
for videoMode in videoModes:
video = videoMode
if videoMode.endswith("23"):
video = "%s.976" % videoMode
if videoMode[-1].isdigit():
video = "%sHz" % videoMode
resList.append((video, videoMode))
videoMode = avControl.getVideoMode("Unknown")
keys = ["green", "yellow", "blue", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
selection = 0
for index, item in enumerate(resList):
if item[1] == videoMode:
selection = index
break
print("[InfoBarGenerics] Current video mode is %s." % videoMode)
self.session.openWithCallback(self.resolutionSelected, ChoiceBox, text=_("Please select a resolution..."), list=resList, keys=keys, selection=selection)
def resolutionSelected(self, videoMode):
if videoMode is not None:
if isinstance(videoMode[1], str):
if videoMode[1] == "exit" or videoMode[1] == "" or videoMode[1] == "auto":
self.ExGreen_toggleGreen()
if videoMode[1] != "auto":
iAVSwitch.setVideoModeDirect(videoMode[1])
self.ExGreen_doHide()
else:
self.ExGreen_doHide()
class InfoBarVmodeButton:
def __init__(self):
self["VmodeButtonActions"] = HelpableActionMap(self, "InfobarVmodeButtonActions", {
"vmodeSelection": (self.vmodeSelection, _("Letterbox zoom")),
}, prio=0, description=_("Zoom Actions"))
def vmodeSelection(self):
self.session.open(VideoMode)
class VideoMode(Screen):
def __init__(self, session):
Screen.__init__(self, session)
self["videomode"] = Label()
self["actions"] = HelpableNumberActionMap(self, ["InfobarVmodeButtonActions"], {
"vmodeSelection": (self.selectVMode, _("Letterbox zoom")),
}, prio=0, description=_("Zoom Actions"))
self.Timer = eTimer()
self.Timer.callback.append(self.quit)
self.selectVMode()
def selectVMode(self):
policy = config.av.policy_43
if hasattr(config.av, "policy_169") and 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("", -maxsize - 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 Exception:
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 previous marked position")),
"jumpNextMark": (self.jumpNextMark, _("Jump to next marked position")),
"toggleMark": (self.toggleMark, _("Toggle a cut mark at the current position"))
}, prio=1, description=_("Marker Actions"))
self.cut_list = []
self.is_closing = False
self.__event_tracker = ServiceEventTracker(screen=self, eventmap={
iPlayableService.evStart: self.__serviceStarted,
iPlayableService.evCuesheetChanged: self.downloadCuesheet,
})
def __serviceStarted(self):
if self.is_closing:
return
# print("new service started! trying to download cuts!")
self.downloadCuesheet()
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)
# print("seekable.getLength() returns:", length)
# 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 "ask" in config.usage.on_movie_start.value or not length[1]:
Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this 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 playLastCB(self, answer):
if answer is True and self.resume_point:
self.doSeek(self.resume_point)
self.hideAfterResume()
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 int(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 uploadCuesheet(self):
cue = self.__getCuesheet()
if cue is None:
# print("upload failed, no cuesheet interface")
return
cue.setCutList(self.cut_list)
def downloadCuesheet(self):
cue = self.__getCuesheet()
if cue is None:
# print("download failed, no cuesheet interface")
self.cut_list = []
else:
self.cut_list = cue.getCutList()
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..."))
}, prio=0, description=_("Teletext Actions"))
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:
def __init__(self):
object.__init__(self)
self["SubtitleSelectionAction"] = HelpableActionMap(self, "InfobarSubtitleSelectionActions", {
"subtitleSelection": (self.subtitleSelection, _("Subtitle selection...")),
}, prio=0, description=_("Subtitle Actions"))
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
})
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 subtitleQuickMenu(self):
service = self.session.nav.getCurrentService()
subtitle = service and service.subtitle()
subtitlelist = subtitle and subtitle.getSubtitleList()
if self.selected_subtitle and self.selected_subtitle != (0, 0, 0, 0):
from Screens.AudioSelection import QuickSubtitlesConfigMenu
self.session.open(QuickSubtitlesConfigMenu, self)
else:
self.subtitleSelection()
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.getCachedSubtitle()
if cachedsubtitle:
self.enableSubtitle(cachedsubtitle)
self.doCenterDVBSubs()
def enableSubtitle(self, selectedSubtitle):
subtitle = self.getCurrentServiceSubtitle()
self.selected_subtitle = selectedSubtitle
if subtitle and self.selected_subtitle:
subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
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 dictionary.
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 Actions"))
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 = False
self.hdmi_enabled_full = False
self.hdmi_enabled_pip = False
if BoxInfo.getItem("HDMIin"):
if not self.hdmi_enabled_full:
self.addExtension((self.getHDMIInFullScreen, self.HDMIInFull, lambda: True), "blue")
if BoxInfo.getItem("HDMIinPiP") and 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-IN Actions"))
def HDMIInLong(self):
if self.LongButtonPressed:
if not hasattr(self.session, "pip") and not self.session.pipshown:
self.session.pip = self.session.instantiateDialog(PictureInPicture)
self.session.pip.playService(hdmiInServiceRef())
self.session.pip.show()
self.session.pipshown = True
self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
elif BoxInfo.getItem("HDMIinPiP"):
curref = self.session.pip.getCurrentService()
if curref and curref.type != eServiceReference.idServiceHDMIIn:
self.session.pip.playService(hdmiInServiceRef())
self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
else:
self.session.pipshown = False
del self.session.pip
def HDMIIn(self):
if not self.LongButtonPressed:
slist = self.servicelist
curref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
if curref and curref.type != eServiceReference.idServiceHDMIIn:
self.session.nav.playService(hdmiInServiceRef())
else:
self.session.nav.playService(slist.servicelist.getCurrent())
def getHDMIInFullScreen(self):
return _("Turn on HDMI-IN Full screen mode") if not self.hdmi_enabled_full else _("Turn off HDMI-IN Full screen mode")
def getHDMIInPiPScreen(self):
return _("Turn on HDMI-IN PiP mode") if not self.hdmi_enabled_pip else _("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(hdmiInServiceRef())
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 != eServiceReference.idServiceHDMIIn:
self.hdmi_enabled_pip = True
self.session.pip.playService(hdmiInServiceRef())
self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
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 != eServiceReference.idServiceHDMIIn:
self.hdmi_enabled_full = True
self.session.nav.playService(hdmiInServiceRef())
else:
self.hdmi_enabled_full = False
self.session.nav.playService(slist.servicelist.getCurrent())
class InfoBarSleepTimer:
def __init__(self):
global keyPressCallback
self.sleepStartTime = 0
self.sleepTimer = eTimer()
self.sleepTimer.callback.append(self.sleepTimerTimeout)
self.energyStartTime = 0
self.energyTimer = eTimer()
self.energyTimer.callback.append(self.energyTimerTimeout)
keyPressCallback.append(self.resetEnergyTimer)
def sleepTimerState(self):
return self.getTimerRemaining(self.sleepTimer, self.sleepStartTime)
def energyTimerState(self):
return self.getTimerRemaining(self.energyTimer, self.energyStartTime)
def getTimerRemaining(self, timer, startTime):
if timer.isActive():
return (startTime - int(time()))
return 0
def setSleepTimer(self, sleepTime, showMessage=True):
self.sleepStartTime = self.setTimer(sleepTime, self.sleepStartTime, self.sleepTimer, _("Sleep timer"), showMessage=showMessage)
def setEnergyTimer(self, energyTime, showMessage=True):
self.energyStartTime = self.setTimer(energyTime, self.energyStartTime, self.energyTimer, _("Energy timer"), showMessage=showMessage)
def resetEnergyTimer(self):
if str(config.usage.energyTimer.value) == config.usage.energyTimer.savedValue: # Don't change energy timer while it is being edited.
self.energyStartTime = self.setTimer(config.usage.energyTimer.value, self.energyStartTime, self.energyTimer, _("Energy timer"), showMessage=False)
def setTimer(self, delay, previous, timer, name, showMessage):
minutes = delay // 60
if delay:
message = "%s\n%s %s" % (_("%s has been activated.") % name, _("Delay:"), _("%d minutes") % minutes)
timer.startLongTimer(delay)
delay = int(time()) + delay
else:
message = _("%s has been disabled.") % name
timer.stop()
delay = 0
if showMessage and delay != previous:
print("[InfoBarGenerics] InfoBarSleepTimer: %s set to %d minutes." % (name, minutes))
Notifications.AddPopup(message, type=MessageBox.TYPE_INFO, timeout=5)
return delay
def sleepTimerTimeout(self):
action = config.usage.sleepTimerAction.value
brand, model, timeout = self.timerTimeout(action, self.setSleepTimer, _("Sleep Timer"))
if brand:
if not Screens.Standby.inStandby:
optionList = [
(_("Yes"), True),
(_("No"), False),
(_("Extend"), "extend")
]
state = _("Standby") if action == "standby" else _("Deep Standby")
message = _("The sleep timer wants to set the %s %s to %s.\n\nDo that now or extend the timer?") % (brand, model, state)
self.session.openWithCallback(self.sleepTimerTimeoutCallback, MessageBox, message, timeout=timeout, list=optionList, default=True, windowTitle=_("Sleep Timer")) # , simple=True
else:
self.timerStandby(action)
def sleepTimerTimeoutCallback(self, answer):
if answer == "extend":
from Screens.SleepTimer import SleepTimer
self.session.open(SleepTimer)
elif answer:
self.timerStandby(config.usage.sleepTimerAction.value)
else:
self.setSleepTimer(0, showMessage=False)
def energyTimerTimeout(self):
action = config.usage.energyTimerAction.value
brand, model, timeout = self.timerTimeout(action, self.setEnergyTimer, _("Energy Timer"))
if brand:
if not Screens.Standby.inStandby:
state = _("Standby") if action == "standby" else _("Deep Standby")
message = _("The energy timer wants to set the %s %s to %s.\n\nPress OK to continue using the %s %s.") % (brand, model, state, brand, model)
self.session.openWithCallback(self.energyTimerTimeoutCallback, MessageBox, message, type=MessageBox.TYPE_WARNING, timeout=timeout, default=True, timeoutDefault=False, windowTitle=_("Energy Timer")) # , simple=True
else:
self.timerStandby(action)
def energyTimerTimeoutCallback(self, answer):
if answer:
self.setEnergyTimer(0, showMessage=False)
else:
self.timerStandby(config.usage.energyTimerAction.value)
def timerTimeout(self, action, timerMethod, name):
brand = BoxInfo.getItem("displaybrand")
model = BoxInfo.getItem("displaymodel")
timeout = int(config.usage.shutdown_msgbox_timeout.value)
if action != "standby":
isRecordTime = abs(self.session.nav.RecordTimer.getNextRecordingTime() - time()) <= 900 or self.session.nav.RecordTimer.getStillRecording() or abs(self.session.nav.RecordTimer.getNextZapTime() - time()) <= 900
isPowerTime = abs(self.session.nav.PowerTimer.getNextPowerManagerTime() - time()) <= 900 or self.session.nav.PowerTimer.isProcessing(exceptTimer=0)
if isRecordTime or isPowerTime:
timerMethod(1800, showMessage=False) # 1800 = 30 minutes.
if not Screens.Standby.inStandby:
message = _("A recording, recording timer or power timer is running or will begin within 15 minutes. %s extended to 30 minutes. Your %s %s will go to Deep Standby after the recording or power timer event.\n\nGo to Deep Standby now?") % (name, brand, model)
self.session.openWithCallback(boundFunction(self.timerStandby, action), MessageBox, message, MessageBox.TYPE_YESNO, timeout=timeout, default=True, windowTitle=name)
return None, None, None
return brand, model, timeout
def timerStandby(self, action, answer=None):
if action == "standby" or answer:
if not Screens.Standby.inStandby:
print("[InfoBarGenerics] InfoBarSleepTimer: Going to Standby.")
self.session.open(Screens.Standby.Standby)
elif answer is None:
if not Screens.Standby.inStandby:
if not Screens.Standby.inTryQuitMainloop:
print("[InfoBarGenerics] InfoBarSleepTimer: Going to Deep Standby.")
self.session.open(Screens.Standby.TryQuitMainloop, 1)
else:
print("[InfoBarGenerics] InfoBarSleepTimer: Going to Deep Standby.")
quitMainloop(1)
# ########################################################################################
# For displayed power or record timer messages in foreground and for callback execution. #
# ########################################################################################
#
class InfoBarOpenOnTopHelper:
def __init__(self):
pass
def openInfoBarMessage(self, message, messageboxtyp, timeout=-1):
try:
self.session.open(MessageBox, message, messageboxtyp, timeout=timeout)
except Exception as e:
print("[InfoBarOpenMessage] Exception:", e)
def openInfoBarMessageWithCallback(self, callback, message, messageboxtyp, timeout=-1, default=True):
try:
self.session.openWithCallback(callback, MessageBox, message, messageboxtyp, timeout=timeout, default=default)
except Exception as e:
print("[InfoBarGenerics] [openInfoBarMessageWithCallback] Exception:", e)
def openInfoBarSession(self, session, option=None):
try:
if option is None:
self.session.open(session)
else:
self.session.open(session, option)
except Exception as e:
print("[InfoBarGenerics] [openInfoBarSession] Exception:", e)
# ################################################################
# Handle bsod (python crashes) and show information after crash. #
# ################################################################
#
class InfoBarHandleBsod:
def __init__(self):
self.lastBsod = 0
self.infoBsodIsShown = False
self.lastestBsodWarning = False
self.checkBsodTimer = eTimer()
self.checkBsodTimer.callback.append(self.checkBsodCallback)
self.checkBsodTimer.start(1000, True)
config.crash.bsodpython_ready.setValue(True)
def checkBsodCallback(self):
self.checkBsodTimer.start(1000, True)
if Screens.Standby.inStandby or self.infoBsodIsShown:
return
bsodcnt = getBsodCounter()
if config.crash.bsodpython.value and self.lastBsod < bsodcnt:
maxbs = int(config.crash.bsodmax.value) or 100
writelog = bsodcnt == 1 or not bsodcnt > int(config.crash.bsodhide.value) or bsodcnt >= maxbs
txt = _("Your Receiver has a Software problem detected. Since the last reboot it has occurred %d times.\n") % bsodcnt
txt += _("(Attention: There will be a restart after %d crashes.)") % maxbs
if writelog:
txt += "\n" + "-" * 80 + "\n"
txt += _("A crash log was %s created in '%s'") % ((_("not"), "")[int(writelog)], config.crash.debug_path.value)
# if not writelog:
# txt += "\n" + "-"*80 + "\n"
# txt += _("(It is set that '%s' crash logs are displayed and written.\nInfo: It will always write the first, last but one and lastest crash log.)") % str(int(config.crash.bsodhide.value) or _("Never"))
if bsodcnt >= maxbs:
txt += "\n" + "-" * 80 + "\n"
txt += _("Warning: This is the last crash before an automatic restart is performed.\n")
txt += _("Should the crash counter be reset to prevent a restart?")
self.lastestBsodWarning = True
try:
self.session.openWithCallback(self.infoBsodCallback, MessageBox, txt, type=MessageBox.TYPE_YESNO if self.lastestBsodWarning else MessageBox.TYPE_ERROR, default=False, close_on_any_key=not self.lastestBsodWarning, typeIcon=MessageBox.TYPE_ERROR)
self.infoBsodIsShown = True
except Exception as e:
# print("[InfoBarHandleBsod] Exception:", e)
self.checkBsodTimer.stop()
self.checkBsodTimer.start(5000, True)
self.infoBsodCallback(False)
raise
self.lastBsod = bsodcnt
def infoBsodCallback(self, ret):
if ret and self.lastestBsodWarning:
resetBsodCounter()
self.infoBsodIsShown = False
self.lastestBsodWarning = False