1
0
mirror of https://github.com/fHDHR/fHDHR_NextPVR.git synced 2025-12-06 09:36:59 -05:00
fHDHR_NextPVR/fHDHR_web/__init__.py
2021-01-20 12:24:44 -05:00

229 lines
8.4 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 .hdhr import fHDHR_HDHR
from .rmg import fHDHR_RMG
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.fhdhr.logger.info("Loading HTTP Pages Endpoints.")
self.pages = fHDHR_Pages(fhdhr)
self.add_endpoints(self.pages, "pages")
self.fhdhr.logger.info("Loading HTTP Files Endpoints.")
self.files = fHDHR_Files(fhdhr)
self.add_endpoints(self.files, "files")
self.fhdhr.logger.info("Loading HTTP Brython Endpoints.")
self.brython = fHDHR_Brython(fhdhr)
self.add_endpoints(self.brython, "brython")
self.fhdhr.logger.info("Loading HTTP HDHR Endpoints.")
self.hdhr = fHDHR_HDHR(fhdhr)
self.add_endpoints(self.hdhr, "hdhr")
self.fhdhr.logger.info("Loading HTTP RMG Endpoints.")
self.rmg = fHDHR_RMG(fhdhr)
self.add_endpoints(self.rmg, "rmg")
self.fhdhr.logger.info("Loading HTTP API Endpoints.")
self.api = fHDHR_API(fhdhr)
self.add_endpoints(self.api, "api")
self.fhdhr.logger.info("Loading HTTP Origin Endpoints.")
self.origin_endpoints = self.fhdhr.originwrapper.origin.origin_web.fHDHR_Origin_Web(fhdhr)
self.add_endpoints(self.origin_endpoints, "origin_endpoints")
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 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["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_list, index_name):
if index_name not in list(self.route_list.keys()):
self.route_list[index_name] = {}
item_list = [x for x in dir(index_list) if self.isapath(x)]
for item in item_list:
endpoints = eval("self.%s.%s.%s" % (index_name, item, "endpoints"))
if isinstance(endpoints, str):
endpoints = [endpoints]
handler = eval("self.%s.%s" % (index_name, item))
endpoint_name = eval("self.%s.%s.%s" % (index_name, item, "endpoint_name"))
try:
endpoint_methods = eval("self.%s.%s.%s" % (index_name, item, "endpoint_methods"))
except AttributeError:
endpoint_methods = ['GET']
try:
endpoint_access_level = eval("self.%s.%s.%s" % (index_name, item, "endpoint_access_level"))
except AttributeError:
endpoint_access_level = 0
try:
pretty_name = eval("self.%s.%s.%s" % (index_name, item, "pretty_name"))
except AttributeError:
pretty_name = endpoint_name
try:
endpoint_default_parameters = eval("self.%s.%s.%s" % (index_name, 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_name not in list(self.route_list[index_name].keys()):
self.route_list[index_name][endpoint_name] = {}
self.route_list[index_name][endpoint_name]["name"] = endpoint_name
self.route_list[index_name][endpoint_name]["endpoints"] = endpoints
self.route_list[index_name][endpoint_name]["endpoint_methods"] = endpoint_methods
self.route_list[index_name][endpoint_name]["endpoint_access_level"] = endpoint_access_level
self.route_list[index_name][endpoint_name]["endpoint_default_parameters"] = endpoint_default_parameters
self.route_list[index_name][endpoint_name]["pretty_name"] = pretty_name
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"]
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")