##########################################################################
# OpenWebif: WebController
##########################################################################
# Copyright (C) 2011 - 2022 E2OpenPlugins
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
##########################################################################
from re import match
from os.path import isfile
from Components.config import config as comp_config
from Screens.InfoBar import InfoBar
from .models.info import getInfo, getCurrentTime, getStatusInfo, getFrontendStatus, testPipStatus
from .models.services import getCurrentService, getBouquets, getServices, getSubServices, getSatellites, getBouquetEpg, getBouquetNowNextEpg, getMultiChannelNowNextEpg, getSearchEpg, getSimilarEpg, getChannelEpg, getNowNextEpg, getAllServices, getPlayableServices, getPlayableService, getParentalControlList, getEvent, getServiceRef, getPicon
from .models.volume import getVolumeStatus, setVolumeUp, setVolumeDown, setVolumeMute, setVolume
from .models.audiotrack import getAudioTracks, setAudioTrack
from .models.control import zapService, remoteControl, setPowerState, getStandbyState
from .models.locations import getLocations, getCurrentLocation, addLocation, removeLocation
from .models.timers import getTimers, addTimer, addTimerByEventId, editTimer, removeTimer, toggleTimerStatus, cleanupTimer, writeTimerList, recordNow, tvbrowser, getSleepTimer, setSleepTimer, getPowerTimer, setPowerTimer, getVPSChannels
from .models.message import sendMessage, getMessageAnswer
from .models.movies import getMovieList, removeMovie, getMovieInfo, movieAction, getAllMovies, getMovieDetails, setMovieResumePoint, MOVIETAGFILE
from .models.config import getSettings, addCollapsedMenu, removeCollapsedMenu, saveConfig, getConfigs, getConfigsSections, getUtcOffset
from .models.stream import getStream, getTS, getStreamSubservices, GetSession
from .models.servicelist import reloadServicesLists
from .models.mediaplayer import mediaPlayerAdd, mediaPlayerRemove, mediaPlayerPlay, mediaPlayerCommand, mediaPlayerCurrent, mediaPlayerList, mediaPlayerLoad, mediaPlayerSave, mediaPlayerFindFile
from .models.plugins import reloadPlugins
from .i18n import _
from .base import BaseController
from .stream import StreamController
from .utilities import getUrlArg, toBinary, toString
from .defaults import PICON_PATH
from .models.epg import EPG
def whoami(request):
port = comp_config.OpenWebif.port.value
proto = 'http'
if request.isSecure():
port = comp_config.OpenWebif.https_port.value
proto = 'https'
ourhost = request.getHeader('host')
m = match(r'.+\:(\d+)$', ourhost)
if m is not None:
port = m.group(1)
return {'proto': proto, 'port': port}
[docs]
class WebController(BaseController):
"""
HTTP Web Controller
Fork of *Enigma2 WebInterface API* as described in e.g.
https://dream.reichholf.net/e2web/.
"""
def __init__(self, session, path=""):
BaseController.__init__(self, path=path, session=session)
self.putChild(b"stream", StreamController(session))
def prePageLoad(self, request):
request.setHeader("content-type", "text/xml")
def testMandatoryArguments(self, request, keys):
for key in keys:
k = toBinary(key)
if k not in list(request.args.keys()):
return {
"result": False,
"message": _("Missing mandatory parameter '%s'") % key
}
if len(request.args[k][0]) == 0:
return {
"result": False,
"message": _("The parameter '%s' can't be empty") % key
}
return None
[docs]
def P_tsstart(self, request):
"""
Request handler for the `tsstart` endpoint.
Start timeshift (?).
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
success = True
try:
InfoBar.instance.startTimeshift()
except Exception: # nosec # noqa: E722
success = False
return self.P_tsstate(request, success)
[docs]
def P_tsstop(self, request):
"""
Request handler for the `tsstop` endpoint.
Stop timeshift (?).
.. note::
Not available in *Enigma2 WebInterface API*.
*TODO: improve after action / save , save+record , nothing
config.timeshift.favoriteSaveAction ....*
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
success = True
oldcheck = False
configitem = None
if hasattr(comp_config.timeshift, "check"):
configitem = comp_config.timeshift.check
elif hasattr(comp_config.usage, "check_timeshift"):
configitem = comp_config.usage.check_timeshift
try:
if configitem and configitem.value:
oldcheck = configitem.value
# don't ask but also don't save
configitem.value = False
configitem.save()
InfoBar.instance.stopTimeshift()
except Exception: # nosec # noqa: E722
success = False
if configitem and configitem.value:
configitem.value = oldcheck
configitem.save()
return self.P_tsstate(request, success)
[docs]
def P_tsstate(self, request, success=True):
"""
Request handler for the `tsstate` endpoint.
Retrieve timeshift status(?).
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return {
"state": success,
"timeshiftEnabled": InfoBar.instance.timeshiftEnabled()
}
[docs]
def P_about(self, request):
"""
Request handler for the `about` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#about
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return {
"info": getInfo(self.session, need_fullinfo=True),
"service": getCurrentService(self.session)
}
def P_statusinfo(self, request):
# we don't need to fill logs with this api (it's called too many times)
self.suppresslog = True
return getStatusInfo(self)
def P_pipinfo(self, request):
return testPipStatus(self)
[docs]
def P_tunersignal(self, request):
"""
Request handler for the `tunersignal` endpoint.
Get tuner signal status(?)
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#signal
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/signal
"""
return getFrontendStatus(self.session)
[docs]
def P_vol(self, request):
"""
Request handler for the `vol` endpoint.
Get/Set current volume setting.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#vol
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
_set = getUrlArg(request, "set")
if _set is None or _set == "state":
return getVolumeStatus()
elif _set == "up":
return setVolumeUp()
elif _set == "down":
return setVolumeDown()
elif _set == "mute":
return setVolumeMute()
elif _set[:3] == "set":
try:
return setVolume(int(_set[3:]))
except ValueError: # nosec # noqa: E722
res = getVolumeStatus()
res["result"] = False
res["message"] = _("Wrong parameter format 'set=%s'. Use set=set15 ") % _set
return res
res = getVolumeStatus()
res["result"] = False
res["message"] = _("Unknown Volume command %s") % _set
return res
[docs]
def P_getaudiotracks(self, request):
"""
Request handler for the `/getaudiotracks` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getaudiotracks
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getAudioTracks(self.session)
[docs]
def P_selectaudiotrack(self, request):
"""
Request handler for the `/selectaudiotrack` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#selectaudiotrack
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/signal
:query int id: audio track ID
"""
try:
audioid = int(request.args[b"id"][0])
except Exception: # nosec # noqa: E722
audioid = -1
return setAudioTrack(self.session, audioid)
[docs]
def P_zap(self, request):
"""
Request handler for the `/zap` endpoint.
Zap to requested service_reference.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#zap
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/zap
:query string sRef: service reference
:query string title: service title
"""
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
title = getUrlArg(request, "title", "")
sref = getUrlArg(request, "sRef")
return zapService(self.session, sref, title)
[docs]
def P_remotecontrol(self, request):
"""
Request handler for the `remotecontrol` endpoint.
Send remote control codes.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#remotecontrol
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
text = getUrlArg(request, "text", "")
if text:
return remoteControl(0, "text", text) # text input do not need type and command
res = self.testMandatoryArguments(request, ["command"])
if res:
return res
key = -1
try:
key = int(request.args[b"command"][0])
except Exception: # nosec # noqa: E722
return {
"result": False,
"message": _("The parameter 'command' must be a number")
}
rctype = getUrlArg(request, "type", "")
rcu = getUrlArg(request, "rcu", "")
return remoteControl(key, rctype, rcu)
[docs]
def P_powerstate(self, request):
"""
Request handler for the `powerstate` endpoint.
Get/set power state of enigma2 device.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#powerstate
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
if b"shift" in list(request.args.keys()):
self.P_set_powerup_without_waking_tv(request)
newstate = getUrlArg(request, "newstate")
if newstate:
return setPowerState(self.session, newstate)
return getStandbyState()
[docs]
def P_supports_powerup_without_waking_tv(self, request):
"""
Request handler for the `supports_powerup_without_waking_tv` endpoint.
Check if 'powerup without waking TV' is available.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
try:
# returns 'True' if the image supports the function "Power on without TV":
with open("/tmp/powerup_without_waking_tv.txt") as fd: # nosec
powerupwithoutwakingtv = fd.read()
if ((powerupwithoutwakingtv == 'True') or (powerupwithoutwakingtv == 'False')):
return True
else:
return False
except OSError: # nosec # noqa: E722
return False
[docs]
def P_set_powerup_without_waking_tv(self, request):
"""
Request handler for the `set_powerup_without_waking_tv` endpoint.
Mark 'powerup without waking TV' being available.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
if self.P_supports_powerup_without_waking_tv(request):
try:
# write "True" to file so that the box will power on ONCE skipping the HDMI-CEC communication:
with open("/tmp/powerup_without_waking_tv.txt", "w") as fd: # nosec
fd.write('True')
return True
except OSError: # nosec # noqa: E722
return False
else:
return False
[docs]
def P_getlocations(self, request):
"""
Request handler for the `getlocations` endpoint.
Retrieve paths where video files are stored.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getlocations
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getLocations()
[docs]
def P_getcurrlocation(self, request):
"""
Request handler for the `getcurrlocation` endpoint.
Get currently selected path where video files are to be stored.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getcurrlocation
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getCurrentLocation()
[docs]
def P_getallservices(self, request):
"""
Request handler for the `getallservices` endpoint.
Retrieve list of services in bouquets.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getallservices
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
mode = "tv"
if b"type" in list(request.args.keys()):
mode = "radio"
noiptv = True if getUrlArg(request, "noiptv", "0") in ("1", "true") else False
nolastscanned = True if getUrlArg(request, "nolastscanned", "0") in ("1", "true") else False
removenamefromsref = True if getUrlArg(request, "removenamefromsref", "0") in ("1", "true") else False
showall = False if getUrlArg(request, "showall", "1") in ("0", "false") else True
showproviders = True if getUrlArg(request, "showproviders", "0") in ("1", "true") else False
excludes = getUrlArg(request, "exclude", "").lower()
excludes = excludes.split(",")
excludeprogram = "program" in excludes
excludevod = "vod" in excludes
excludeiptv = "iptv" in excludes
excludelastscanned = "lastscanned" in excludes
showstreamrelay = True if getUrlArg(request, "showstreamrelay", "0") in ("1", "true") else False
bouquets = getAllServices(mode, noiptv=noiptv or excludeiptv, nolastscanned=nolastscanned or excludelastscanned, removenamefromsref=removenamefromsref, showall=showall, showproviders=showproviders, excludeprogram=excludeprogram, excludevod=excludevod, showstreamrelay=showstreamrelay)
if b"renameserviceforxmbc" in list(request.args.keys()):
for bouquet in bouquets["services"]:
for service in bouquet["subservices"]:
if not int(service["servicereference"].split(":")[1]) & 64:
service["servicename"] = f"{service['pos']} - {service['servicename']}"
return bouquets
[docs]
def P_getservices(self, request):
"""
Request handler for the `getservices` endpoint.
Retrieve list of bouquets.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getservices
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
sref = getUrlArg(request, "sRef", "")
hidden = True if getUrlArg(request, "hidden", "0") in ("1", "true") else False
showproviders = True if getUrlArg(request, "showproviders", "0") in ("1", "true") else False
# FALLBACK for old 3rd party tools
if getUrlArg(request, "provider") == "1":
showproviders = True
picon = True if getUrlArg(request, "picon", "0") in ("1", "true") else False
removenamefromsref = True if getUrlArg(request, "removenamefromsref", "0") in ("1", "true") else False
showstreamrelay = True if getUrlArg(request, "showstreamrelay", "0") in ("1", "true") else False
noiptv = True if getUrlArg(request, "noiptv", "0") in ("1", "true") else False
showall = False if getUrlArg(request, "showall", "1") in ("0", "false") else True
return getServices(sref=sref, showall=showall, showhidden=hidden, showproviders=showproviders, picon=picon, removenamefromsref=removenamefromsref, noiptv=noiptv, showstreamrelay=showstreamrelay)
[docs]
def P_servicesxspf(self, request):
"""
Request handler for the `servicesxspf` endpoint.
Retrieve list of bouquets(?) in XSPF format.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/services.xspf
:query string bRef: bouquet reference
"""
bref = getUrlArg(request, "bRef", "")
request.setHeader('Content-Type', 'application/xspf+xml')
bouquetname = getUrlArg(request, "bName")
if bouquetname:
bouquetname = bouquetname.replace(",", "_").replace(";", "_")
request.setHeader('Content-Disposition', f'inline; filename={bouquetname}.xspf;')
services = getServices(bref, False)
if comp_config.OpenWebif.auth_for_streaming.value:
session = GetSession()
if session.GetAuth(request) is not None:
auth = ':'.join(session.GetAuth(request)) + "@"
else:
auth = f"-sid:{session.GetSID(request)}@"
else:
auth = ''
portnumber = comp_config.OpenWebif.streamport.value
services["host"] = f"{request.getRequestHostname()}:{portnumber}"
services["auth"] = auth
services["bname"] = bouquetname
return services
[docs]
def P_servicesm3u(self, request):
"""
Request handler for the `servicesm3u` endpoint.
Retrieve list of bouquets(?) in M3U format.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#servicesm3u
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/services.m3u
:query string bRef: bouquet reference
"""
bref = getUrlArg(request, "bRef", "")
request.setHeader('Content-Type', 'application/x-mpegurl')
bouquetname = getUrlArg(request, "bName")
if bouquetname:
bouquetname = bouquetname.replace(",", "_").replace(";", "_")
request.setHeader('Content-Disposition', f'inline; filename={bouquetname}.m3u8;')
services = getServices(bref, False)
if comp_config.OpenWebif.auth_for_streaming.value:
session = GetSession()
if session.GetAuth(request) is not None:
auth = ':'.join(session.GetAuth(request)) + "@"
else:
auth = f"-sid:{session.GetSID(request)}@"
else:
auth = ''
portnumber = comp_config.OpenWebif.streamport.value
services["host"] = f"{request.getRequestHostname()}:{portnumber}"
services["auth"] = auth
return services
[docs]
def P_subservices(self, request):
"""
Request handler for the `subservices` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#subservices
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getSubServices(self.session)
[docs]
def P_parentcontrollist(self, request):
"""
Request handler for the `parentcontrollist` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#parentcontrollist
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getParentalControlList()
[docs]
def P_servicelistplayable(self, request):
"""
Request handler for the `servicelistplayable` endpoint.
Retrieve list of 'playable' bouquets.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#servicelistplayable
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
sref = getUrlArg(request, "sRef", "")
srefplaying = getUrlArg(request, "sRefPlaying", "")
return getPlayableServices(sref, srefplaying)
[docs]
def P_serviceplayable(self, request):
"""
Request handler for the `serviceplayable` endpoint.
Check if referenced service is 'playable'.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#serviceplayable
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
sref = getUrlArg(request, "sRef", "")
srefplaying = getUrlArg(request, "sRefPlaying", "")
return getPlayableService(sref, srefplaying)
[docs]
def P_addlocation(self, request):
"""
Request handler for the `addlocation` endpoint.
Add a path to the list of paths where video files are stored.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#addlocation
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["dirname"])
if res:
return res
dirname = getUrlArg(request, "dirname")
create = getUrlArg(request, "createFolder") == "1"
return addLocation(dirname, create)
[docs]
def P_removelocation(self, request):
"""
Request handler for the `removelocation` endpoint.
Remove a path from the list of paths where video files are stored.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#removelocation
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["dirname"])
if res:
return res
dirname = getUrlArg(request, "dirname")
remove = getUrlArg(request, "removeFolder") == "1"
return removeLocation(dirname, remove)
[docs]
def P_message(self, request):
"""
Request handler for the `message` endpoint.
Display a message on the screen attached to enigma2 device.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#message
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["text", "type"])
if res:
return res
try:
ttype = int(request.args[b"type"][0])
except ValueError:
return {
"result": False,
"message": _("type %s is not a number") % request.args[b"type"][0]
}
timeout = -1
if b"timeout" in list(request.args.keys()):
try:
timeout = int(request.args[b"timeout"][0])
except ValueError:
pass
text = getUrlArg(request, "text")
return sendMessage(self.session, text, ttype, timeout)
[docs]
def P_messageanswer(self, request):
"""
Request handler for the `messageanswer` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#messageanswer
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getMessageAnswer()
[docs]
def P_movielist(self, request):
"""
Request handler for the `movielist` endpoint.
Retrieve list of movie items. (alternative implementation)
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#movielist
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getMovieList(request.args)
def P_fullmovielist(self, request):
return getAllMovies()
[docs]
def P_movielisthtml(self, request):
"""
Request handler for the `movielisthtml` endpoint.
Retrieve list of movie items in HTML format.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#movielisthtml
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
request.setHeader("content-type", "text/html")
return getMovieList(request.args)
[docs]
def P_movielistm3u(self, request):
"""
Request handler for the `movielistm3u` endpoint.
Retrieve list of movie items in M3U format.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#movielistm3u
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
request.setHeader('Content-Type', 'application/x-mpegurl')
movielist = getMovieList(request.args)
movielist["host"] = f"{whoami(request)['proto']}://{request.getRequestHostname()}:{whoami(request)['port']}"
return movielist
[docs]
def P_moviedelete(self, request):
"""
Request handler for the `moviedelete` endpoint.
Delete movie file.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#moviedelete
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
sref = getUrlArg(request, "sRef")
force = getUrlArg(request, "force") is not None
return removeMovie(self.session, sref, force)
[docs]
def P_moviemove(self, request):
"""
Request handler for the `moviemove` endpoint.
Move movie file.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#moviemove
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
res = self.testMandatoryArguments(request, ["dirname"])
if res:
return res
sref = getUrlArg(request, "sRef")
dirname = getUrlArg(request, "dirname")
return movieAction(self.session, sref, dirname, domove=True)
[docs]
def P_moviecopy(self, request):
"""
Request handler for the `moviecopy` endpoint.
Copy movie file.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#moviecopy
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
res = self.testMandatoryArguments(request, ["dirname"])
if res:
return res
sref = getUrlArg(request, "sRef")
dirname = getUrlArg(request, "dirname")
return movieAction(self.session, sref, dirname)
[docs]
def P_movierename(self, request):
"""
Request handler for the `movierename` endpoint.
Rename movie file.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#movierename
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
res = self.testMandatoryArguments(request, ["newname"])
if res:
return res
sref = getUrlArg(request, "sRef")
newname = getUrlArg(request, "newname")
return movieAction(self.session, sref, None, True, newname)
# DEPRECATED use movieinfo
[docs]
def P_movieinfo(self, request):
"""
Request handler for the `movie` endpoint.
Add/Remove tags to movie file. Multiple tags needs to separate by ,
Remame title of movie.
Get/set movie cuts.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#movieinfo
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
sref = getUrlArg(request, "sRef")
if sref is None:
sref = getUrlArg(request, "sref")
if sref:
addtag = getUrlArg(request, "addtag")
deltag = getUrlArg(request, "deltag")
title = getUrlArg(request, "title")
cuts = getUrlArg(request, "cuts")
desc = getUrlArg(request, "desc")
return getMovieInfo(sref, addtag, deltag, title, cuts, desc, True)
else:
return getMovieInfo()
[docs]
def P_moviedetails(self, request):
"""
Request handler for the `movie` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#moviedetails
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
sref = getUrlArg(request, "sRef")
if sref is None:
sref = getUrlArg(request, "sref")
if sref:
return getMovieDetails(sref)
else:
return {
"result": False
}
def P_movieresumepoint(self, request):
sref = getUrlArg(request, "sRef")
if sref is None:
sref = getUrlArg(request, "sref")
try:
resumepoint = int(request.args[b"resumepoint"][0]) * 90000 # in seconds
except (ValueError, KeyError): # nosec # noqa: E722
resumepoint = None
if sref and resumepoint:
return setMovieResumePoint(sref, resumepoint)
else:
return {
"result": False
}
# VPS Plugin
[docs]
def vpsparams(self, request):
"""
VPS related helper function(?)
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
vpsplugin_enabled = getUrlArg(request, "vpsplugin_enabled") == "1"
vpsplugin_overwrite = getUrlArg(request, "vpsplugin_overwrite") == "1"
vpsplugin_time = None
if b"vpsplugin_time" in request.args:
vpsplugin_time = int(float(request.args[b"vpsplugin_time"][0]))
if vpsplugin_time == -1:
vpsplugin_time = None
# partnerbox:
vps_pbox = getUrlArg(request, "vps_pbox")
if vps_pbox:
vpsplugin_enabled = None
vpsplugin_overwrite = None
if "yes_safe" in vps_pbox:
vpsplugin_enabled = True
elif "yes" in vps_pbox:
vpsplugin_enabled = True
vpsplugin_overwrite = True
return {
"vpsplugin_time": vpsplugin_time,
"vpsplugin_overwrite": vpsplugin_overwrite,
"vpsplugin_enabled": vpsplugin_enabled
}
[docs]
def P_vpschannels(self, request):
"""
Request handler for the `vpschannels` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getVPSChannels(self.session)
[docs]
def P_timerlist(self, request):
"""
Request handler for the `timerlist` endpoint.
Retrieve list of timers.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timerlist
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
ret = getTimers(self.session)
ret["locations"] = comp_config.movielist.videodirs.value
ret["default"] = comp_config.usage.default_path.value
tags = []
if isfile(MOVIETAGFILE):
try:
with open(MOVIETAGFILE) as fd:
for tag in fd.read().split("\n"):
if tag:
tags.append(tag.strip())
except OSError:
pass
ret["tags"] = tags
return ret
def _AddEditTimer(self, request, mode):
returntimer = getUrlArg(request, "returntimer") == "1"
disabled = getUrlArg(request, "disabled") == "1"
justplay = getUrlArg(request, "justplay") == "1"
afterevent = getUrlArg(request, "afterevent", "3")
if afterevent in ["0", "1", "2", "3"]:
afterevent = int(afterevent)
else:
afterevent = 3
dirname = getUrlArg(request, "dirname")
if dirname is not None and len(dirname) == 0:
dirname = None
tags = []
_tags = getUrlArg(request, "tags")
if _tags:
tags = _tags.split(' ')
repeated = int(getUrlArg(request, "repeated", "0"))
description = getUrlArg(request, "description", "")
sref = getUrlArg(request, "sRef")
eit = 0
if mode == 1:
try:
eventid = int(request.args[b"eventid"][0])
except ValueError: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'eventid' must be a number"
}
elif b"eit" in list(request.args.keys()) and isinstance(request.args[b"eit"][0], int):
eit = int(request.args[b"eit"][0])
else:
# This might need further investigation. Do not get exactly the middle, take 20% so we usually expect to get first event.
queryTime = int(request.args[b"begin"][0]) + (int(request.args[b"end"][0]) - int(request.args[b"begin"][0])) // 5
epg = EPG()
eventid = epg.getEventIdByTime(sref, queryTime)
if eventid is not None:
eit = int(eventid)
always_zap = int(getUrlArg(request, "always_zap", "-1"))
pipzap = int(getUrlArg(request, "pipzap", "-1"))
allow_duplicate = getUrlArg(request, "allow_duplicate") == "1"
recordingtype = getUrlArg(request, "recordingtype")
if recordingtype:
if recordingtype not in ("normal", "descrambled", "scrambled"):
recordingtype = None
marginBefore = int(getUrlArg(request, "marginbefore", "-1"))
marginAfter = int(getUrlArg(request, "marginafter", "-1"))
hasEndTime = getUrlArg(request, "hasendtime")
if hasEndTime:
hasEndTime = hasEndTime == "1"
# TODO: merge function addTimer+editTimer+addTimerByEventId in timers.py
if mode == 1:
return addTimerByEventId(
self.session,
eventid,
sref,
justplay,
dirname,
tags,
self.vpsparams(request),
always_zap,
afterevent,
pipzap,
allow_duplicate,
recordingtype,
marginBefore,
marginAfter,
hasEndTime,
returntimer
)
elif mode == 2:
try:
beginold = int(request.args[b"beginOld"][0])
except ValueError: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'beginOld' must be a number"
}
try:
endold = int(request.args[b"endOld"][0])
except ValueError: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'endOld' must be a number"
}
return editTimer(
self.session,
sref,
getUrlArg(request, "begin"),
getUrlArg(request, "end"),
getUrlArg(request, "name"),
description,
disabled,
justplay,
afterevent,
dirname,
tags,
repeated,
getUrlArg(request, "channelOld"),
beginold,
endold,
recordingtype,
self.vpsparams(request),
always_zap,
pipzap,
allow_duplicate,
marginBefore,
marginAfter,
hasEndTime,
returntimer
)
else:
return addTimer(
self.session,
sref,
getUrlArg(request, "begin"),
getUrlArg(request, "end"),
getUrlArg(request, "name"),
description,
disabled,
justplay,
afterevent,
dirname,
tags,
repeated,
recordingtype,
self.vpsparams(request),
None,
eit,
always_zap,
pipzap,
allow_duplicate,
marginBefore,
marginAfter,
hasEndTime,
returntimer
)
[docs]
def P_timeradd(self, request):
"""
Request handler for the `timeradd` endpoint.
Add timer
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timeradd
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef", "begin", "end", "name"])
if res:
return res
return self._AddEditTimer(request, 0)
[docs]
def P_timeraddbyeventid(self, request):
"""
Request handler for the `timeraddbyeventid` endpoint.
Add timer by event ID
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timeraddbyeventid
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/timeraddbyeventid
:query string sRef: service reference
:query int eventid: Event ID
:query int justplay: *Just Play* indicator
:query string dirname: target path(?)
:query string tags: tags to add(?)
:query int always_zap: always zap first(?)
:query int afterevent: afterevent state
"""
res = self.testMandatoryArguments(request, ["sRef", "eventid"])
if res:
return res
return self._AddEditTimer(request, 1)
[docs]
def P_timerchange(self, request):
"""
Request handler for the `timerchange` endpoint.
Change timer
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timerchange
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/timerchange
:query string sRef: service reference
:query int begin: begin timestamp
:query int end: end timestamp
:query string name: name
:query string description: description
:query string channelOld: old channel(?)
:query int beginOld: old begin timestamp(?)
:query int endOld: old end timestamp(?)
:query int justplay: *Just Play* indicator
:query string dirname: target path(?)
:query string tags: tags to add(?)
:query int always_zap: always zap first(?)
:query int disabled: disabled state
:query int afterevent: afterevent state
"""
res = self.testMandatoryArguments(request, ["sRef", "begin", "end", "name", "channelOld", "beginOld", "endOld"])
if res:
return res
return self._AddEditTimer(request, 2)
[docs]
def P_timertogglestatus(self, request):
"""
Request handler for the `timertogglestatus` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef", "begin", "end"])
if res:
return res
try:
begin = int(request.args[b"begin"][0])
except Exception: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'begin' must be a number"
}
try:
end = int(request.args[b"end"][0])
except Exception: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'end' must be a number"
}
return toggleTimerStatus(self.session, getUrlArg(request, "sRef"), begin, end)
[docs]
def P_timerdelete(self, request):
"""
Request handler for the `timerdelete` endpoint.
Delete timer
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timerdelete
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef", "begin", "end"])
if res:
return res
try:
begin = int(request.args[b"begin"][0])
except Exception: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'begin' must be a number"
}
try:
end = int(request.args[b"end"][0])
except Exception: # nosec # noqa: E722
return {
"result": False,
"message": "The parameter 'end' must be a number"
}
try:
eit = int(request.args[b"eit"][0])
except Exception: # nosec # noqa: E722
eit = None
return removeTimer(self.session, getUrlArg(request, "sRef"), begin, end, eit)
[docs]
def P_timercleanup(self, request):
"""
Request handler for the `timercleanup` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timercleanup
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return cleanupTimer(self.session)
[docs]
def P_timerlistwrite(self, request):
"""
Request handler for the `timerlistwrite` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#timerlistwrite
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return writeTimerList(self.session)
[docs]
def P_recordnow(self, request):
"""
Request handler for the `recordnow` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#recordnow
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
infinite = False
if b"undefinitely" in list(request.args.keys()) or b"infinite" in list(request.args.keys()):
infinite = True
return recordNow(self.session, infinite)
[docs]
def P_currenttime(self, request):
"""
Request handler for the `currenttime` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#currenttime
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getCurrentTime()
[docs]
def P_deviceinfo(self, request):
"""
Request handler for the `deviceinfo` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#deviceinfo
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getInfo(session=self.session, need_fullinfo=True)
def P_getipv6(self, request):
request.setHeader("content-type", "text/html")
firstpublic = ''
info = getInfo()['ifaces']
for iface in info:
public = iface['firstpublic']
if public is not None:
firstpublic = public
break
return {
"firstpublic": firstpublic
}
# http://enigma2/api/epgbouquet?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20%22userbouquet.favourites.tv%22%20ORDER%20BY%20bouquet
# http://enigma2/web/epgbouquet?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20%22userbouquet.favourites.tv%22%20ORDER%20BY%20bouquet
# TODO: this is _woefully_ inefficient
def P_epgbouquet(self, request):
res = self.testMandatoryArguments(request, ["bRef"])
if res:
return res
begintime = -1
if b"time" in list(request.args.keys()):
try:
begintime = int(request.args[b"time"][0])
except ValueError:
pass
endtime = None
if b"endTime" in list(request.args.keys()):
try:
endtime = int(request.args[b"endTime"][0])
except ValueError:
pass
return getBouquetEpg(getUrlArg(request, "bRef"), begintime, endtime, self.isJson)
# http://enigma2/api/epgmulti?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
# http://enigma2/web/epgmulti?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
# TODO: check if originally dupe of `P_epgbouquet`
[docs]
def P_epgmulti(self, request):
"""
Request handler for the `epgmulti` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["bRef"])
if res:
return res
begintime = -1
if b"time" in list(request.args.keys()):
try:
begintime = int(request.args[b"time"][0])
except ValueError:
pass
endtime = -1
if b"endTime" in list(request.args.keys()):
try:
endtime = int(request.args[b"endTime"][0])
except ValueError:
pass
return getBouquetEpg(getUrlArg(request, "bRef"), begintime, endtime, self.isJson)
[docs]
def P_epgxmltv(self, request):
"""
Request handler for the `epgxmltv` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
bRef: mandatory, method uses epgmulti
lang: mandatory, needed for xmltv and Enigma2 has no parameter for epg language
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["bRef", "lang"])
if res:
return res
ret = self.P_epgmulti(request)
bref = getUrlArg(request, "bRef")
ret["services"] = getServices(bref, True, False)["services"]
ret["lang"] = getUrlArg(request, "lang")
ret["offset"] = getUtcOffset()
return ret
# http://enigma2/api/epgnow?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
# http://enigma2/web/epgnow?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
def P_epgnow(self, request):
return self.epgnownext(request, EPG.NOW)
# http://enigma2/api/epgnext?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
# http://enigma2/web/epgnext?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
def P_epgnext(self, request):
return self.epgnownext(request, EPG.NEXT)
# http://enigma2/api/epgnownext?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
# http://enigma2/web/epgnownext?bRef=1%3A7%3A1%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A%20FROM%20BOUQUET%20"userbouquet.favourites.tv"%20ORDER%20BY%20bouquet
def P_epgnownext(self, request):
return self.epgnownext(request, EPG.NOW_NEXT)
def epgnownext(self, request, nowornext):
res = self.testMandatoryArguments(request, ["bRef"])
if res:
return res
bref = getUrlArg(request, "bRef")
showisplayable = getUrlArg(request, "showIsPlayable") is not None
showstreamrelay = True if getUrlArg(request, "showstreamrelay", "0") in ("1", "true") else False
ret = getBouquetNowNextEpg(bref, nowornext, self.isJson, showisplayable=showisplayable, showstreamrelay=showstreamrelay)
if nowornext == EPG.NOW_NEXT:
info = getCurrentService(self.session)
ret["info"] = info
return ret
def P_epgmultichannelnownext(self, request):
res = self.testMandatoryArguments(request, ["sRefs"])
if res:
return res
srefs = getUrlArg(request, "sRefs").split(",")
ret = getMultiChannelNowNextEpg(srefs, self.isJson)
return str(ret) # fixed Jun'22 (seems to have been broken for quite a while)
# http://enigma2/api/epgsearch?search=test
# http://enigma2/web/epgsearch?search=test
[docs]
def P_epgsearch(self, request):
"""
EPG event search and lookup handler.
.. note::
One may use
:py:func:`controllers.events.EventsController.search` for
searching events.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#epgsearch
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
search = getUrlArg(request, "search")
if search:
endtime = None
if b"endtime" in list(request.args.keys()):
try:
endtime = int(request.args[b"endtime"][0])
except ValueError:
pass
fulldesc = False
if b"full" in list(request.args.keys()):
fulldesc = True
return getSearchEpg(search, endtime, fulldesc, False, self.isJson)
else:
res = self.testMandatoryArguments(request, ["eventid"])
if res:
return res
sref = getUrlArg(request, "sRef")
if sref is None:
sref = getUrlArg(request, "sref")
if sref is None:
return {
"result": False,
"message": _("The parameter '%s' can't be empty") % "sRef,sref"
}
item_id = 0
try:
item_id = int(request.args[b"eventid"][0])
except ValueError:
pass
return getEvent(sref, item_id, self.isJson)
# http://enigma2/api/epgsearchrss?search=test
# http://enigma2/web/epgsearchrss?search=test
def P_epgsearchrss(self, request):
res = self.testMandatoryArguments(request, ["search"])
if res:
return res
search = getUrlArg(request, "search")
ret = getSearchEpg(search)
ret["title"] = f"EPG Search '{search}'"
ret["generator"] = "OpenWebif"
ret["description"] = f"{len(ret['events'])} result for '{search}'"
return ret
# http://enigma2/api/epgservice?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
# http://enigma2/web/epgservice?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
def P_epgservice(self, request):
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
begintime = -1
if b"time" in list(request.args.keys()):
try:
begintime = int(request.args[b"time"][0])
except ValueError:
pass
endtime = -1
if b"endTime" in list(request.args.keys()):
try:
endtime = int(request.args[b"endTime"][0])
except ValueError:
pass
return getChannelEpg(getUrlArg(request, "sRef"), begintime, endtime, self.isJson)
# http://enigma2/api/epgservicenow?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
# http://enigma2/web/epgservicenow?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
def P_epgservicenow(self, request):
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
return getNowNextEpg(getUrlArg(request, "sRef"), EPG.NOW, self.isJson)
# http://enigma2/api/epgservicenext?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
# http://enigma2/web/epgservicenext?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
def P_epgservicenext(self, request):
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
return getNowNextEpg(getUrlArg(request, "sRef"), EPG.NEXT, self.isJson)
def P_epgservicenownext(self, request):
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
eventnow = getNowNextEpg(getUrlArg(request, "sRef"), EPG.NOW, self.isJson)
eventnext = getNowNextEpg(getUrlArg(request, "sRef"), EPG.NEXT, self.isJson)
eventnow = eventnow["events"][0] if eventnow["events"] else {}
eventnext = eventnext["events"][0] if eventnext["events"] else {}
return {"events": [eventnow, eventnext]}
# http://enigma2/api/epgsimilar?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A&eventid=32645
# http://enigma2/web/epgsimilar?sRef=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A&eventid=32645
def P_epgsimilar(self, request):
res = self.testMandatoryArguments(request, ["sRef", "eventid"])
if res:
return res
try:
eventid = int(request.args[b"eventid"][0])
except ValueError:
return {
"result": False,
"message": "The parameter 'eventid' must be a number"
}
return getSimilarEpg(getUrlArg(request, "sRef"), eventid, self.isJson)['events']
# http://enigma2/api/event?idev=32695&sref=1%3A0%3A19%3A1B1F%3A802%3A2%3A11A0000%3A0%3A0%3A0%3A
# (/web/event returns a 404 in both `classic` and `modern` interfaces
def P_event(self, request):
sref = getUrlArg(request, "sRef")
if sref is None:
sref = getUrlArg(request, "sref")
event = getEvent(sref, request.args[b"idev"][0], self.isJson)
if event is not None:
# TODO: this shouldn't really be part of an event's data
event['event']['recording_margin_before'] = comp_config.recording.margin_before.value
event['event']['recording_margin_after'] = comp_config.recording.margin_after.value
return event
else:
return None
# http://enigma2/api/getcurrent
# http://enigma2/web/getcurrent
[docs]
def P_getcurrent(self, request):
"""
Request handler for the `getcurrent` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getcurrent
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/getcurrent
"""
info = getCurrentService(self.session)
eventnow = getNowNextEpg(info["ref"], EPG.NOW, self.isJson)
if len(eventnow["events"]) > 0:
eventnow = eventnow["events"][0]
eventnow["provider"] = info["provider"]
else:
eventnow = {
"id": 0,
"begin_timestamp": 0,
"duration_sec": 0,
"title": "",
"shortdesc": "",
"longdesc": "",
"sref": "",
"sname": "",
"now_timestamp": 0,
"remaining": 0,
"provider": "",
"genre": "",
"genreid": 0
}
eventnext = getNowNextEpg(info["ref"], EPG.NEXT, self.isJson)
if len(eventnext["events"]) > 0:
eventnext = eventnext["events"][0]
eventnext["provider"] = info["provider"]
else:
eventnext = {
"id": 0,
"begin_timestamp": 0,
"duration_sec": 0,
"title": "",
"shortdesc": "",
"longdesc": "",
"sref": "",
"sname": "",
"now_timestamp": 0,
"remaining": 0,
"provider": "",
"genre": "",
"genreid": 0
}
# replace EPG NOW with Movie info
mnow = eventnow
if info["ref"].startswith('1:0:0:0:0:0:0:0:0:0:/'):
try:
mnow["sref"] = info["ref"]
service = self.session.nav.getCurrentService()
minfo = service and service.info()
movie = minfo and minfo.getEvent(0)
if movie and minfo:
mnow["title"] = movie.getEventName()
mnow["shortdesc"] = movie.getShortDescription()
mnow["longdesc"] = movie.getExtendedDescription()
mnow["begin_timestamp"] = movie.getBeginTime()
mnow["duration_sec"] = movie.getDuration()
mnow["remaining"] = movie.getDuration()
mnow["id"] = movie.getEventId()
except Exception: # nosec # noqa: E722
mnow = eventnow
elif mnow["sref"] == '':
serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
if serviceref is not None:
try:
if serviceref.toString().startswith('4097:0:0:0:0:0:0:0:0:0:/'):
from enigma import eServiceCenter
servicehandler = eServiceCenter.getInstance()
sinfo = servicehandler.info(serviceref)
if sinfo:
mnow["title"] = sinfo.getName(serviceref)
servicepath = serviceref and serviceref.getPath()
if servicepath and servicepath.startswith("/"):
mnow["filename"] = servicepath
mnow["sref"] = serviceref.toString()
except Exception: # nosec
pass
return {
"info": info,
"now": mnow,
"next": eventnext
}
[docs]
def P_getpid(self, request):
"""
Request handler for the `getpid` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#getpid
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
request.setHeader("content-type", "text/html")
info = getCurrentService(self.session)
return {
"ppid": f"{info['pmtpid']:x}",
"vpid": f"{info['vpid']:x}",
"apid": f"{info['apid']:x}",
"host": request.getRequestHostname()
}
def P_collapsemenu(self, request):
res = self.testMandatoryArguments(request, ["name"])
if res:
return res
return addCollapsedMenu(getUrlArg(request, "name"))
def P_expandmenu(self, request):
res = self.testMandatoryArguments(request, ["name"])
if res:
return res
return removeCollapsedMenu(getUrlArg(request, "name"))
[docs]
def P_streamm3u(self, request):
"""
Request handler for the `streamm3u` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#streamm3u
.. note::
Parameters Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/stream.m3u
:query string ref: service reference
:query string name: service name
"""
self.isCustom = True
if comp_config.OpenWebif.webcache.zapstream.value:
ref = getUrlArg(request, "ref")
if ref:
name = getUrlArg(request, "name", "")
zapService(self.session, ref, name, stream=True)
return getStream(self.session, request, "stream.m3u")
[docs]
def P_tsm3u(self, request):
"""
Request handler for the `tsm3u` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#tsm3u
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/ts.m3u
:query string file: filename of the stream
"""
self.isCustom = True
return getTS(self.session, request)
def P_videom3u(self, request):
self.isCustom = True
return getStream(self.session, request, "video.m3u")
[docs]
def P_streamcurrentm3u(self, request):
"""
Request handler for the `streamcurrentm3u` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#streamcurrentm3u
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/streamcurrent.m3u
"""
self.isCustom = True
return getStream(self.session, request, "streamcurrent.m3u")
[docs]
def P_streamsubservices(self, request):
"""
Request handler for the `streamsubservices` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#streamsubservices
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/streamsubservices
:query string sRef: service reference
"""
return getStreamSubservices(self.session, request)
[docs]
def P_servicelistreload(self, request):
"""
Reload service lists, transponders, parental control black-/white lists
or/and lamedb.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#servicelistreload
.. http:get:: /web/servicelistreload
:query string mode: [0=both, 1=lamedb only, 2=userbouqets only, 3=transponders, 4=parentalcontrol white-/blacklist]
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["mode"])
if res:
return res
mode = getUrlArg(request, "mode")
return reloadServicesLists(mode)
[docs]
def P_tvbrowser(self, request):
"""
Request handler for the `tvbrowser` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#tvbrowser
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return tvbrowser(self.session, request)
[docs]
def P_saveconfig(self, request):
"""
Request handler for the `saveconfig` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:post:: /web/saveconfig
:query string key: configuration key
:query string value: configuration value
"""
if request.method == b'POST':
res = self.testMandatoryArguments(request, ["key"])
if res:
return res
value = getUrlArg(request, "value")
if value:
key = getUrlArg(request, "key")
return saveConfig(key, value)
return {"result": False}
def P_mediaplayeradd(self, request):
res = self.testMandatoryArguments(request, ["file"])
if res:
return res
return mediaPlayerAdd(self.session, getUrlArg(request, "file"))
def P_mediaplayerplay(self, request):
res = self.testMandatoryArguments(request, ["file"])
if res:
return res
root = getUrlArg(request, "root", "")
return mediaPlayerPlay(self.session, getUrlArg(request, "file"), root)
def P_mediaplayercmd(self, request):
res = self.testMandatoryArguments(request, ["command"])
if res:
return res
return mediaPlayerCommand(self.session, getUrlArg(request, "command"))
def P_mediaplayercurrent(self, request):
return mediaPlayerCurrent(self.session)
def P_mediaplayerfindfile(self, request):
path = getUrlArg(request, "path", "/media/")
pattern = getUrlArg(request, "pattern", "*.*")
return mediaPlayerFindFile(self.session, path, pattern)
def P_mediaplayerlist(self, request):
path = getUrlArg(request, "path", "")
types = getUrlArg(request, "types", "")
return mediaPlayerList(self.session, path, types)
def P_mediaplayerremove(self, request):
res = self.testMandatoryArguments(request, ["file"])
if res:
return res
return mediaPlayerRemove(self.session, getUrlArg(request, "file"))
def P_mediaplayerload(self, request):
res = self.testMandatoryArguments(request, ["filename"])
if res:
return res
return mediaPlayerLoad(self.session, getUrlArg(request, "filename"))
def P_mediaplayerwrite(self, request):
res = self.testMandatoryArguments(request, ["filename"])
if res:
return res
return mediaPlayerSave(self.session, getUrlArg(request, "filename"))
[docs]
def P_pluginlistread(self, request):
"""
Request handler for the `pluginlistread` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#pluginlistread
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return reloadPlugins()
[docs]
def P_restarttwisted(self, request):
"""
Request handler for the `restarttwisted` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#restarttwisted
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
from Plugins.Extensions.OpenWebif.httpserver import HttpdRestart
HttpdRestart(self.session)
return ""
def P_powertimer(self, request):
if len(request.args):
res = self.testMandatoryArguments(request, ["start", "end", "timertype", "repeated", "afterevent", "disabled"])
if res:
return res
return setPowerTimer(self.session, request)
else:
return getPowerTimer(self.session, request)
[docs]
def P_sleeptimer(self, request):
"""
Request handler for the `sleeptimer` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#sleeptimer
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
.. http:get:: /web/sleeptimer
:query string cmd: command (*get* or *set*)
:query int time: time in minutes (*0* -- *999*)
:query string action: action (*standby* or *shutdown*)
:query string enabled: enabled (*True* or *False*)
:query string confirmed: confirmed (supported?)
"""
cmd = getUrlArg(request, "cmd", "get")
if cmd == "get":
return getSleepTimer(self.session)
time = getUrlArg(request, "time")
if time:
try:
time = int(time)
if time > 999:
time = 999
elif time < 0:
time = 0
except ValueError:
pass
action = getUrlArg(request, "action", "standby")
enabled = getUrlArg(request, "enabled")
enabled = enabled and enabled.lower() == "true"
ret = getSleepTimer(self.session)
if cmd != "set":
ret["message"] = f"ERROR: Obligatory parameter 'cmd' [get,set] has unspecified value '{cmd}'"
return ret
if time is None and enabled is True: # it's used only if the timer is enabled
ret["message"] = "ERROR: Obligatory parameter 'time' [0-999] is missing"
return ret
if enabled is None:
ret["message"] = "Obligatory parameter 'enabled' [True,False] is missing"
return ret
return setSleepTimer(self.session, time, action, enabled)
[docs]
def P_external(self, request):
"""
Request handler for the `external` endpoint.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#external
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
try:
from Plugins.Extensions.WebInterface.WebChilds.Toplevel import loaded_plugins
result = []
for p in loaded_plugins:
result.append((p[0], '', p[2], p[3]))
return {
"plugins": result
}
except Exception:
return {
"plugins": []
}
[docs]
def P_settings(self, request):
"""
Request handler for the `settings` endpoint.
Retrieve list of key/kalue pairs of device configuration.
.. seealso::
https://github.com/oe-alliance/OpenWebif/wiki/OpenWebif-API-documentation#settings
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
return getSettings()
[docs]
def P_bouquets(self, request):
"""
Request handler for the `boquets` endpoint.
Get list of tuples (bouquet reference, bouquet name) for available
bouquets.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
stype = getUrlArg(request, "stype", "tv")
return getBouquets(stype)
def P_epgmultigz(self, request):
return self.P_epgmulti(request)
def P_getsatellites(self, request):
stype = getUrlArg(request, "stype", "tv")
return getSatellites(stype)
[docs]
def P_saveepg(self, request):
"""
Request handler for the `saveepg` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
EPG().save()
return {
"result": True,
"message": "EPG data saved"
}
[docs]
def P_loadepg(self, request):
"""
Request handler for the `loadepg` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
EPG().load()
return {
"result": True,
"message": "EPG data loaded"
}
[docs]
def P_getsubtitles(self, request):
"""
Request handler for the `getsubtitles` endpoint.
.. note::
Not available in *Enigma2 WebInterface API*.
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
service = self.session.nav.getCurrentService()
ret = {"subtitlelist": [], "result": False}
subtitle = service and service.subtitle()
subtitlelist = subtitle and subtitle.getSubtitleList()
if subtitlelist:
for i in list(range(0, len(subtitlelist))):
ret["result"] = True
subt = subtitlelist[i]
ret["subtitlelist"].append({
"type": subt[0],
"pid": subt[1],
"page_nr": subt[2],
"mag_nr": subt[3],
"lang": subt[4]
})
return ret
def P_setmoviesort(self, request):
nsort = getUrlArg(request, "nsort")
if nsort:
comp_config.OpenWebif.webcache.moviesort.value = nsort
comp_config.OpenWebif.webcache.moviesort.save()
return {}
def P_css(self, request):
request.setHeader("content-type", "text/css")
ret = {}
theme = 'original'
if comp_config.OpenWebif.webcache.theme.value:
theme = comp_config.OpenWebif.webcache.theme.value
ret['theme'] = theme
moviedb = comp_config.OpenWebif.webcache.moviedb.value if comp_config.OpenWebif.webcache.moviedb.value else 'IMDb'
ret['moviedb'] = moviedb
ret['showchanneldetails'] = comp_config.OpenWebif.webcache.showchanneldetails.value
smallremote = comp_config.OpenWebif.webcache.smallremote.value if comp_config.OpenWebif.webcache.smallremote.value else 'new'
ret['smallremote'] = smallremote
return ret
def P_config(self, request):
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
setcs = getConfigsSections()
if request.path == b'/api/config':
return setcs
else:
try:
rp = toString(request.path)
sect = rp.split('/')
if len(sect) == 4:
cfgs = getConfigs(sect[3])
resultcfgs = []
for cfg in cfgs['configs']:
_min = -1
kv = []
data = cfg['data']
if 'choices' in data:
for ch in data['choices']:
if type(ch).__name__ == 'tuple' and len(ch) == 2 and ch[0] == ch[1]:
if RepresentsInt(ch[0]):
kv.append(int(ch[0]))
else:
kv = []
break
else:
kv = []
break
if len(kv) > 1 and kv[1] == (kv[0] + 1):
_min = kv[0]
_max = kv[len(kv) - 1]
if _min > -1:
data['min'] = _min
data['max'] = _max
del data['choices']
cfg['data'] = data
resultcfgs.append(cfg)
else:
resultcfgs.append(cfg)
return {'configs': resultcfgs}
except Exception:
# TODO show exception
pass
return {}
def P_setwebconfig(self, request):
args = list(request.args.keys())
for arg in args:
sarg = toString(arg)
if sarg in ("minmovielist", "mintimerlist", "minepglist", "rcu_full_view", "epgsearch_full", "epgsearch_only_bq", "nownext_columns", "responsive_enabled", "showpicons", "showchanneldetails", "showiptvchannelsinselection", "screenshotchannelname", "showallpackages", "showepghistory", "zapstream", "screenshot_high_resolution", "screenshot_refresh_auto"):
val = request.args[arg][0] in (b"true", b"1")
configitem = getattr(comp_config.OpenWebif.webcache, sarg)
configitem.value = val
configitem.save()
return {"result": True}
elif sarg in ("moviedb", "smallremote", "theme"):
try:
configitem = getattr(comp_config.OpenWebif.webcache, sarg)
configitem.value = getUrlArg(request, sarg)
configitem.save()
except Exception:
pass
return {"result": True}
elif sarg in ("mepgmode", "screenshot_refresh_time"):
try:
configitem = getattr(comp_config.OpenWebif.webcache, sarg)
configitem.value = int(request.args[arg][0])
configitem.save()
except Exception:
pass
return {"result": True}
return {"result": False}
[docs]
def P_getserviceref(self, request):
"""
Get the serviceref from name.
.. http:get:: /api/getserviceref
:query string name: service name to find
:query string searchinBouquetsOnly: must be 'true'
:query string bRef: define only one single bouquet where to find
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["name"])
if res:
return res
name = getUrlArg(request, "name")
bref = getUrlArg(request, "bRef")
searchinbouquetsonly = (getUrlArg(request, "searchinBouquetsOnly") == 'true')
return getServiceRef(name, searchinbouquetsonly, bref)
[docs]
def P_getpicon(self, request):
"""
Get the picon from service.
.. http:get:: /api/getpicon
:query string sRef: service refrerence
:query string path: path of the picons
:query string json: result as json
Args:
request (twisted.web.server.Request): HTTP request object
Returns:
HTTP response with headers
"""
res = self.testMandatoryArguments(request, ["sRef"])
if res:
return res
path = getUrlArg(request, "path")
sref = getUrlArg(request, "sRef")
json = getUrlArg(request, "json")
pp = getPicon(sref, path, False)
if pp:
if path is None:
path = PICON_PATH
link = pp
pp = pp.replace("/picon/", path)
if json == 'true':
if pp:
return {"result": True, "path": pp, "link": link}
else:
return {"result": False}
else:
self.isImage = True
return pp
def P_setthememode(self, request):
thememode = getUrlArg(request, "themeMode")
if thememode:
print(f"save theme mode: {thememode}")
comp_config.OpenWebif.responsive_themeMode.value = thememode
comp_config.OpenWebif.responsive_themeMode.save()
return {}
def P_setskincolor(self, request):
skincolor = getUrlArg(request, "skincolor")
if skincolor:
print(f"save color: {skincolor}")
comp_config.OpenWebif.responsive_skinColor.value = skincolor
comp_config.OpenWebif.responsive_skinColor.save()
return {}
[docs]
class ApiController(WebController):
def __init__(self, session, path=""):
WebController.__init__(self, session, path)
def prePageLoad(self, request):
self.isJson = True