mirror of
https://github.com/fHDHR/fHDHR_NextPVR.git
synced 2025-12-06 09:26:57 -05:00
230 lines
8.8 KiB
Python
230 lines
8.8 KiB
Python
from gevent.pywsgi import WSGIServer
|
|
from flask import Flask, request, session
|
|
import threading
|
|
import uuid
|
|
|
|
from .pages import fHDHR_Pages
|
|
from .files import fHDHR_Files
|
|
from .brython import fHDHR_Brython
|
|
from .api import fHDHR_API
|
|
|
|
|
|
fHDHR_web_VERSION = "v0.8.1-beta"
|
|
|
|
|
|
class fHDHR_HTTP_Server():
|
|
app = None
|
|
|
|
def __init__(self, fhdhr):
|
|
self.fhdhr = fhdhr
|
|
|
|
self.template_folder = fhdhr.config.internal["paths"]["www_templates_dir"]
|
|
|
|
self.fhdhr.logger.info("Loading Flask.")
|
|
|
|
self.fhdhr.app = Flask("fHDHR", template_folder=self.template_folder)
|
|
self.instance_id = str(uuid.uuid4())
|
|
|
|
# Allow Internal API Usage
|
|
self.fhdhr.app.testing = True
|
|
self.fhdhr.api.client = self.fhdhr.app.test_client()
|
|
|
|
# Set Secret Key For Sessions
|
|
self.fhdhr.app.secret_key = self.fhdhr.config.dict["fhdhr"]["friendlyname"]
|
|
|
|
self.route_list = {}
|
|
|
|
self.endpoints_obj = {}
|
|
self.endpoints_obj["pages"] = fHDHR_Pages(fhdhr)
|
|
self.endpoints_obj["files"] = fHDHR_Files(fhdhr)
|
|
self.endpoints_obj["brython"] = fHDHR_Brython(fhdhr)
|
|
self.endpoints_obj["api"] = fHDHR_API(fhdhr)
|
|
|
|
self.selfadd_web_plugins()
|
|
for endpoint_type in list(self.endpoints_obj.keys()):
|
|
self.fhdhr.logger.info("Loading HTTP %s Endpoints." % endpoint_type)
|
|
self.add_endpoints(endpoint_type)
|
|
|
|
self.fhdhr.app.before_request(self.before_request)
|
|
self.fhdhr.app.after_request(self.after_request)
|
|
self.fhdhr.app.before_first_request(self.before_first_request)
|
|
|
|
self.fhdhr.threads["flask"] = threading.Thread(target=self.run)
|
|
|
|
def selfadd_web_plugins(self):
|
|
for plugin_name in list(self.fhdhr.plugins.plugins.keys()):
|
|
if self.fhdhr.plugins.plugins[plugin_name].type == "web":
|
|
method = self.fhdhr.plugins.plugins[plugin_name].name.lower()
|
|
plugin_utils = self.fhdhr.plugins.plugins[plugin_name].plugin_utils
|
|
try:
|
|
self.endpoints_obj[method] = self.fhdhr.plugins.plugins[plugin_name].Plugin_OBJ(self.fhdhr, plugin_utils)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def start(self):
|
|
self.fhdhr.logger.info("Flask HTTP Thread Starting")
|
|
self.fhdhr.threads["flask"].start()
|
|
|
|
def stop(self):
|
|
self.fhdhr.logger.info("Flask HTTP Thread Stopping")
|
|
self.http.stop()
|
|
|
|
def before_first_request(self):
|
|
self.fhdhr.logger.info("HTTP Server Online.")
|
|
|
|
def before_request(self):
|
|
|
|
session["session_id"] = str(uuid.uuid4())
|
|
session["instance_id"] = self.instance_id
|
|
session["route_list"] = self.route_list
|
|
|
|
session["user_agent"] = request.headers.get('User-Agent')
|
|
|
|
session["is_internal_api"] = self.detect_internal_api(request)
|
|
if session["is_internal_api"]:
|
|
self.fhdhr.logger.debug("Client is using internal API call.")
|
|
|
|
session["is_mobile"] = self.detect_mobile(request)
|
|
if session["is_mobile"]:
|
|
self.fhdhr.logger.debug("Client is a mobile device.")
|
|
|
|
session["is_plexmediaserver"] = self.detect_plexmediaserver(request)
|
|
if session["is_plexmediaserver"]:
|
|
self.fhdhr.logger.debug("Client is a Plex Media Server.")
|
|
|
|
session["deviceauth"] = self.detect_plexmediaserver(request)
|
|
|
|
session["tuner_used"] = None
|
|
|
|
session["restart"] = False
|
|
|
|
self.fhdhr.logger.debug("Client %s requested %s Opening" % (request.method, request.path))
|
|
|
|
def after_request(self, response):
|
|
|
|
# Close Tuner if it was in use, and did not close already
|
|
# if session["tuner_used"] is not None:
|
|
# tuner = self.fhdhr.device.tuners.tuners[str(session["tuner_used"])]
|
|
# if tuner.tuner_lock.locked():
|
|
# self.fhdhr.logger.info("Shutting down Tuner #%s after Request." % session["tuner_used"])
|
|
# tuner.close()
|
|
|
|
self.fhdhr.logger.debug("Client %s requested %s Closing" % (request.method, request.path))
|
|
if not session["restart"]:
|
|
return response
|
|
else:
|
|
return self.stop()
|
|
|
|
def detect_internal_api(self, request):
|
|
user_agent = request.headers.get('User-Agent')
|
|
if not user_agent:
|
|
return False
|
|
elif str(user_agent).lower().startswith("fhdhr"):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def detect_deviceauth(self, request):
|
|
return request.args.get('DeviceAuth', default=None, type=str)
|
|
|
|
def detect_mobile(self, request):
|
|
user_agent = request.headers.get('User-Agent')
|
|
phones = ["iphone", "android", "blackberry"]
|
|
if not user_agent:
|
|
return False
|
|
elif any(phone in user_agent.lower() for phone in phones):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def detect_plexmediaserver(self, request):
|
|
user_agent = request.headers.get('User-Agent')
|
|
if not user_agent:
|
|
return False
|
|
elif str(user_agent).lower().startswith("plexmediaserver"):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def add_endpoints(self, index_name):
|
|
|
|
item_list = [x for x in dir(self.endpoints_obj[index_name]) if self.isapath(x)]
|
|
endpoint_main = self.endpoints_obj[index_name]
|
|
endpoint_main.fhdhr.version # dummy line
|
|
for item in item_list:
|
|
endpoints = eval("endpoint_main.%s.%s" % (item, "endpoints"))
|
|
if isinstance(endpoints, str):
|
|
endpoints = [endpoints]
|
|
handler = eval("endpoint_main.%s" % item)
|
|
endpoint_name = eval("endpoint_main.%s.%s" % (item, "endpoint_name"))
|
|
|
|
try:
|
|
endpoint_methods = eval("endpoint_main.%s.%s" % (item, "endpoint_methods"))
|
|
except AttributeError:
|
|
endpoint_methods = ['GET']
|
|
|
|
try:
|
|
endpoint_access_level = eval("endpoint_main.%s.%s" % (item, "endpoint_access_level"))
|
|
except AttributeError:
|
|
endpoint_access_level = 0
|
|
|
|
try:
|
|
pretty_name = eval("endpoint_main.%s.%s" % (item, "pretty_name"))
|
|
except AttributeError:
|
|
pretty_name = endpoint_name
|
|
|
|
try:
|
|
endpoint_category = eval("endpoint_main.%s.%s" % (item, "endpoint_category"))
|
|
except AttributeError:
|
|
endpoint_category = index_name
|
|
|
|
try:
|
|
endpoint_default_parameters = eval("endpoint_main.%s.%s" % (item, "endpoint_default_parameters"))
|
|
except AttributeError:
|
|
endpoint_default_parameters = {}
|
|
|
|
self.fhdhr.logger.debug("Adding endpoint %s available at %s with %s methods." % (endpoint_name, ",".join(endpoints), ",".join(endpoint_methods)))
|
|
|
|
if endpoint_category not in list(self.route_list.keys()):
|
|
self.route_list[endpoint_category] = {}
|
|
|
|
if endpoint_name not in list(self.route_list[endpoint_category].keys()):
|
|
self.route_list[endpoint_category][endpoint_name] = {}
|
|
self.route_list[endpoint_category][endpoint_name]["name"] = endpoint_name
|
|
self.route_list[endpoint_category][endpoint_name]["endpoints"] = endpoints
|
|
self.route_list[endpoint_category][endpoint_name]["endpoint_methods"] = endpoint_methods
|
|
self.route_list[endpoint_category][endpoint_name]["endpoint_access_level"] = endpoint_access_level
|
|
self.route_list[endpoint_category][endpoint_name]["endpoint_default_parameters"] = endpoint_default_parameters
|
|
self.route_list[endpoint_category][endpoint_name]["pretty_name"] = pretty_name
|
|
self.route_list[endpoint_category][endpoint_name]["endpoint_category"] = endpoint_category
|
|
|
|
for endpoint in endpoints:
|
|
self.add_endpoint(endpoint=endpoint,
|
|
endpoint_name=endpoint_name,
|
|
handler=handler,
|
|
methods=endpoint_methods)
|
|
|
|
def isapath(self, item):
|
|
not_a_page_list = ["fhdhr", "plugin_utils"]
|
|
if item in not_a_page_list:
|
|
return False
|
|
elif item.startswith("__") and item.endswith("__"):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=['GET']):
|
|
self.fhdhr.app.add_url_rule(endpoint, endpoint_name, handler, methods=methods)
|
|
|
|
def run(self):
|
|
|
|
self.http = WSGIServer(self.fhdhr.api.address_tuple,
|
|
self.fhdhr.app.wsgi_app,
|
|
log=self.fhdhr.logger.logger,
|
|
error_log=self.fhdhr.logger.logger)
|
|
try:
|
|
self.http.serve_forever()
|
|
self.stop()
|
|
except AttributeError:
|
|
self.fhdhr.logger.info("HTTP Server Offline")
|