mirror of
https://github.com/fHDHR/fHDHR_NextPVR.git
synced 2025-12-06 16:46:58 -05:00
Add Settings Page, and overhaul Config system
This commit is contained in:
parent
e98c53526d
commit
38e98d7000
@ -24,7 +24,7 @@
|
||||
# update_frequency = 43200
|
||||
|
||||
[ffmpeg]
|
||||
# ffmpeg_path = ffmpeg
|
||||
# path = ffmpeg
|
||||
# bytes_per_read = 1152000
|
||||
|
||||
[direct_stream]
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
[main]
|
||||
uuid =
|
||||
cache_dir =
|
||||
thread_method = multiprocessing
|
||||
|
||||
[fhdhr]
|
||||
address = 0.0.0.0
|
||||
discovery_address = 0.0.0.0
|
||||
port = 5004
|
||||
reporting_manufacturer = BoronDust
|
||||
reporting_model = fHDHR
|
||||
reporting_firmware_ver = 20201001
|
||||
reporting_tuner_type = Antenna
|
||||
device_auth = fHDHR
|
||||
require_auth = False
|
||||
|
||||
[epg]
|
||||
images = pass
|
||||
|
||||
[ffmpeg]
|
||||
ffmpeg_path = ffmpeg
|
||||
bytes_per_read = 1152000
|
||||
|
||||
[vlc]
|
||||
vlc_path = cvlc
|
||||
bytes_per_read = 1152000
|
||||
|
||||
[direct_stream]
|
||||
chunksize = 1048576
|
||||
|
||||
[logging]
|
||||
level = WARNING
|
||||
|
||||
[database]
|
||||
type = sqlite
|
||||
driver = None
|
||||
148
data/internal_config/fhdhr.json
Normal file
148
data/internal_config/fhdhr.json
Normal file
@ -0,0 +1,148 @@
|
||||
{
|
||||
"main":{
|
||||
"uuid":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"cache_dir":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"thread_method":{
|
||||
"value": "multiprocessing",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"fhdhr":{
|
||||
"address":{
|
||||
"value": "0.0.0.0",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"discovery_address":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"port":{
|
||||
"value": 5004,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"reporting_manufacturer":{
|
||||
"value": "BoronDust",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"reporting_model":{
|
||||
"value": "fHDHR",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"reporting_firmware_ver":{
|
||||
"value": "20201001",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"reporting_tuner_type":{
|
||||
"value": "Antenna",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"device_auth":{
|
||||
"value": "fHDHR",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"require_auth":{
|
||||
"value": false,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"epg":{
|
||||
"images":{
|
||||
"value": "pass",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"ffmpeg":{
|
||||
"path":{
|
||||
"value": "ffmpeg",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"bytes_per_read":{
|
||||
"value": 1152000,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"vlc":{
|
||||
"path":{
|
||||
"value": "cvlc",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"bytes_per_read":{
|
||||
"value": 1152000,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"direct_stream":{
|
||||
"chunksize":{
|
||||
"value": 1048576,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"logging":{
|
||||
"level":{
|
||||
"value": "WARNING",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"database":{
|
||||
"type":{
|
||||
"value": "sqlite",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"driver":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"user":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"pass":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"host":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"port":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"name":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
[main]
|
||||
servicename = NextPVR
|
||||
dictpopname = nextpvr
|
||||
reponame = fHDHR_NextPVR
|
||||
required = nextpvr/pin
|
||||
valid_epg_methods = None,blocks,origin,zap2it
|
||||
|
||||
[fhdhr]
|
||||
friendlyname = fHDHR-NextPVR
|
||||
stream_type = direct
|
||||
tuner_count = 4
|
||||
reporting_firmware_name = fHDHR_NextPVR
|
||||
|
||||
[epg]
|
||||
method = origin
|
||||
update_frequency = 43200
|
||||
|
||||
[nextpvr]
|
||||
address = localhost
|
||||
port = 8866
|
||||
ssl = False
|
||||
pin =
|
||||
weight = 300
|
||||
epg_update_frequency = 43200
|
||||
sid =
|
||||
91
data/internal_config/serviceconf.json
Normal file
91
data/internal_config/serviceconf.json
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
"main":{
|
||||
"servicename":{
|
||||
"value": "NextPVR",
|
||||
"config_file": false,
|
||||
"config_web": false
|
||||
},
|
||||
"dictpopname":{
|
||||
"value": "nextpvr",
|
||||
"config_file": false,
|
||||
"config_web": false
|
||||
},
|
||||
"reponame":{
|
||||
"value": "fHDHR_NextPVR",
|
||||
"config_file": false,
|
||||
"config_web": false
|
||||
},
|
||||
"valid_epg_methods":{
|
||||
"value": "None,blocks,origin,zap2it",
|
||||
"config_file": false,
|
||||
"config_web": false
|
||||
},
|
||||
"required":{
|
||||
"value": "nextpvr/pin",
|
||||
"config_file": false,
|
||||
"config_web": false
|
||||
}
|
||||
},
|
||||
"fhdhr":{
|
||||
"friendlyname":{
|
||||
"value": "fHDHR-NextPVR",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"stream_type":{
|
||||
"value": "direct",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"tuner_count":{
|
||||
"value": 4,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"reporting_firmware_name":{
|
||||
"value": "fHDHR_NextPVR",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"epg":{
|
||||
"method":{
|
||||
"value": "origin",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"update_frequency":{
|
||||
"value": 43200,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
}
|
||||
},
|
||||
"nextpvr":{
|
||||
"address":{
|
||||
"value": "localhost",
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"port":{
|
||||
"value": 8866,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"ssl":{
|
||||
"value": false,
|
||||
"config_file": true,
|
||||
"config_web": true
|
||||
},
|
||||
"pin":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": true,
|
||||
"config_web_hidden": true
|
||||
},
|
||||
"sid":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
[zap2it]
|
||||
delay = 5
|
||||
postalcode =
|
||||
affiliate_id = gapzap
|
||||
country = USA
|
||||
device = -
|
||||
headendid = lineupId
|
||||
isoverride = True
|
||||
languagecode = en
|
||||
pref =
|
||||
timespan = 6
|
||||
timezone =
|
||||
userid = -
|
||||
64
data/internal_config/zap2it.json
Normal file
64
data/internal_config/zap2it.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"zap2it":{
|
||||
"delay":{
|
||||
"value": 5,
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"postalcode":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"affiliate_id":{
|
||||
"value": "gapzap",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"country":{
|
||||
"value": "USA",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"device":{
|
||||
"value": "-",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"headendid":{
|
||||
"value": "lineupId",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"isoverride":{
|
||||
"value": true,
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"languagecode":{
|
||||
"value": "en",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"pref":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"timespan":{
|
||||
"value": 6,
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"timezone":{
|
||||
"value": "none",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
},
|
||||
"userid":{
|
||||
"value": "-",
|
||||
"config_file": true,
|
||||
"config_web": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@
|
||||
<button class="pull-left" onclick="OpenLink('/xmltv')">xmltv</a></button>
|
||||
<button class="pull-left" onclick="OpenLink('/version')">Version</a></button>
|
||||
<button class="pull-left" onclick="OpenLink('/diagnostics')">Diagnostics</a></button>
|
||||
<button class="pull-left" onclick="OpenLink('/settings')">Settings</a></button>
|
||||
|
||||
<a class="pull-right" style="padding: 5px;" href="/api/xmltv?method=get&source={{ fhdhr.device.epg.def_method }}">xmltv</a>
|
||||
<a class="pull-right" style="padding: 5px;" href="/api/m3u?method=get&channel=all">m3u</a>
|
||||
|
||||
60
data/www/templates/settings.html
Normal file
60
data/www/templates/settings.html
Normal file
@ -0,0 +1,60 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h4 style="text-align: center;">fHDHR Settings</h4>
|
||||
|
||||
<h4 style="text-align: center;">Settings will require a manual restart.</h4>
|
||||
|
||||
{% for config_section in list(web_settings_dict.keys()) %}
|
||||
|
||||
{% if config_section == "origin" %}
|
||||
<h4 style="text-align: center;">{{ fhdhr.config.dict["main"]["dictpopname"] }}</h4>
|
||||
{% else %}
|
||||
<h4 style="text-align: center;">{{ config_section }}</h4>
|
||||
{% endif %}
|
||||
|
||||
<table class="center" style="width:100%">
|
||||
<tr>
|
||||
<th>Config Name</th>
|
||||
<th>Config Default Value</th>
|
||||
<th>Config Value</th>
|
||||
<th>Update</th>
|
||||
<th>Reset</th>
|
||||
</tr>
|
||||
|
||||
{% for config_item in list(web_settings_dict[config_section].keys()) %}
|
||||
|
||||
<tr>
|
||||
<td data-th="Config Name">{{ config_item }}</td>
|
||||
|
||||
<td data-th="Config Default Value">{{ web_settings_dict[config_section][config_item]["value_default"] }}</td>
|
||||
|
||||
<form method="post" action="/api/settings?method=update&redirect=%2Fsettings">
|
||||
<input type="hidden" name="config_section" value={{ config_section }}>
|
||||
<input type="hidden" name="config_name" value={{ config_item }}>
|
||||
<input type="hidden" name="config_default" value={{ web_settings_dict[config_section][config_item]["value_default"] }}>
|
||||
{% if web_settings_dict[config_section][config_item]["hide"] %}
|
||||
<td data-th="Config Value"><input type="text" size="50" name="config_value" value=**************></td>
|
||||
{% else %}
|
||||
<td data-th="Config Value"><input type="text" size="50" name="config_value" value={{ web_settings_dict[config_section][config_item]["value"] }}></td>
|
||||
{% endif %}
|
||||
<td data-th="Update"><input type="submit" value="Update"></td>
|
||||
</form>
|
||||
|
||||
<form method="post" action="/api/settings?method=update&redirect=%2Fsettings">
|
||||
<input type="hidden" name="config_section" value={{ config_section }}>
|
||||
<input type="hidden" name="config_name" value={{ config_item }}>
|
||||
<input type="hidden" name="config_value" value={{ web_settings_dict[config_section][config_item]["value_default"] }}>
|
||||
<input type="hidden" name="config_default" value={{ web_settings_dict[config_section][config_item]["value_default"] }}>
|
||||
<td data-th="Reset"><input type="submit" value="Reset"></td>
|
||||
</form>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
@ -5,6 +5,7 @@ import pathlib
|
||||
import logging
|
||||
import subprocess
|
||||
import platform
|
||||
import json
|
||||
|
||||
import fHDHR.exceptions
|
||||
from fHDHR.tools import isint, isfloat, is_arithmetic, is_docker
|
||||
@ -13,42 +14,148 @@ from fHDHR.tools import isint, isfloat, is_arithmetic, is_docker
|
||||
class Config():
|
||||
|
||||
def __init__(self, filename, script_dir):
|
||||
self.internal = {}
|
||||
self.conf_default = {}
|
||||
self.dict = {}
|
||||
self.config_file = filename
|
||||
self.parser = configparser.RawConfigParser(allow_no_value=True)
|
||||
|
||||
self.load_defaults(script_dir)
|
||||
|
||||
print("Loading Configuration File: " + str(self.config_file))
|
||||
self.read_config(self.config_file)
|
||||
|
||||
self.initial_load(script_dir)
|
||||
self.config_verification()
|
||||
|
||||
def load_defaults(self, script_dir):
|
||||
def initial_load(self, script_dir):
|
||||
|
||||
data_dir = pathlib.Path(script_dir).joinpath('data')
|
||||
www_dir = pathlib.Path(data_dir).joinpath('www')
|
||||
|
||||
self.dict["filedir"] = {
|
||||
self.internal["paths"] = {
|
||||
"script_dir": script_dir,
|
||||
"data_dir": data_dir,
|
||||
|
||||
"cache_dir": pathlib.Path(data_dir).joinpath('cache'),
|
||||
"internal_config": pathlib.Path(data_dir).joinpath('internal_config'),
|
||||
"www_dir": www_dir,
|
||||
"www_images_dir": pathlib.Path(www_dir).joinpath('images'),
|
||||
"www_templates_dir": pathlib.Path(www_dir).joinpath('templates'),
|
||||
"font": pathlib.Path(data_dir).joinpath('garamond.ttf'),
|
||||
"favicon": pathlib.Path(data_dir).joinpath('favicon.ico'),
|
||||
"epg_cache": {},
|
||||
}
|
||||
|
||||
for conffile in os.listdir(self.dict["filedir"]["internal_config"]):
|
||||
conffilepath = os.path.join(self.dict["filedir"]["internal_config"], conffile)
|
||||
if str(conffilepath).endswith(".ini"):
|
||||
self.read_config(conffilepath)
|
||||
for conffile in os.listdir(self.internal["paths"]["internal_config"]):
|
||||
conffilepath = os.path.join(self.internal["paths"]["internal_config"], conffile)
|
||||
if str(conffilepath).endswith(".json"):
|
||||
self.read_json_config(conffilepath)
|
||||
|
||||
def read_config(self, conffilepath):
|
||||
print("Loading Configuration File: " + str(self.config_file))
|
||||
self.read_ini_config(self.config_file)
|
||||
|
||||
self.load_versions()
|
||||
|
||||
def load_versions(self):
|
||||
|
||||
self.internal["versions"] = {
|
||||
"opersystem": None,
|
||||
"isdocker": False,
|
||||
"ffmpeg": "N/A",
|
||||
"vlc": "N/A"
|
||||
}
|
||||
|
||||
opersystem = platform.system()
|
||||
self.internal["versions"]["opersystem"] = opersystem
|
||||
if opersystem in ["Linux", "Darwin"]:
|
||||
# Linux/Mac
|
||||
if os.getuid() == 0 or os.geteuid() == 0:
|
||||
print('Warning: Do not run fHDHR with root privileges.')
|
||||
elif opersystem in ["Windows"]:
|
||||
# Windows
|
||||
if os.environ.get("USERNAME") == "Administrator":
|
||||
print('Warning: Do not run fHDHR as Administrator.')
|
||||
else:
|
||||
print("Uncommon Operating System, use at your own risk.")
|
||||
|
||||
isdocker = is_docker()
|
||||
self.internal["versions"]["isdocker"] = isdocker
|
||||
|
||||
if self.dict["fhdhr"]["stream_type"] == "ffmpeg":
|
||||
try:
|
||||
ffmpeg_command = [self.dict["ffmpeg"]["path"],
|
||||
"-version",
|
||||
"pipe:stdout"
|
||||
]
|
||||
|
||||
ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE)
|
||||
ffmpeg_version = ffmpeg_proc.stdout.read()
|
||||
ffmpeg_proc.terminate()
|
||||
ffmpeg_proc.communicate()
|
||||
ffmpeg_version = ffmpeg_version.decode().split("version ")[1].split(" ")[0]
|
||||
except FileNotFoundError:
|
||||
ffmpeg_version = "Missing"
|
||||
print("Failed to find ffmpeg.")
|
||||
self.internal["versions"]["ffmpeg"] = ffmpeg_version
|
||||
|
||||
if self.dict["fhdhr"]["stream_type"] == "vlc":
|
||||
try:
|
||||
vlc_command = [self.dict["vlc"]["path"],
|
||||
"--version",
|
||||
"pipe:stdout"
|
||||
]
|
||||
|
||||
vlc_proc = subprocess.Popen(vlc_command, stdout=subprocess.PIPE)
|
||||
vlc_version = vlc_proc.stdout.read()
|
||||
vlc_proc.terminate()
|
||||
vlc_proc.communicate()
|
||||
vlc_version = vlc_version.decode().split("version ")[1].split('\n')[0]
|
||||
except FileNotFoundError:
|
||||
vlc_version = "Missing"
|
||||
print("Failed to find vlc.")
|
||||
self.internal["versions"]["vlc"] = vlc_version
|
||||
|
||||
def read_json_config(self, conffilepath):
|
||||
with open(conffilepath, 'r') as jsonconf:
|
||||
confimport = json.load(jsonconf)
|
||||
for section in list(confimport.keys()):
|
||||
|
||||
if section not in self.dict.keys():
|
||||
self.dict[section] = {}
|
||||
|
||||
if section not in self.conf_default.keys():
|
||||
self.conf_default[section] = {}
|
||||
|
||||
for key in list(confimport[section].keys()):
|
||||
|
||||
if key not in list(self.conf_default[section].keys()):
|
||||
self.conf_default[section][key] = {}
|
||||
|
||||
confvalue = confimport[section][key]["value"]
|
||||
if isint(confvalue):
|
||||
confvalue = int(confvalue)
|
||||
elif isfloat(confvalue):
|
||||
confvalue = float(confvalue)
|
||||
elif is_arithmetic(confvalue):
|
||||
confvalue = eval(confvalue)
|
||||
elif "," in confvalue:
|
||||
confvalue = confvalue.split(",")
|
||||
elif str(confvalue).lower() in ["none"]:
|
||||
confvalue = None
|
||||
elif str(confvalue).lower() in ["false"]:
|
||||
confvalue = False
|
||||
elif str(confvalue).lower() in ["true"]:
|
||||
confvalue = True
|
||||
|
||||
self.dict[section][key] = confvalue
|
||||
|
||||
self.conf_default[section][key]["value"] = confvalue
|
||||
|
||||
for config_option in ["config_web_hidden", "config_file", "config_web"]:
|
||||
if config_option not in list(confimport[section][key].keys()):
|
||||
config_option_value = False
|
||||
else:
|
||||
config_option_value = confimport[section][key][config_option]
|
||||
if str(config_option_value).lower() in ["none"]:
|
||||
config_option_value = None
|
||||
elif str(config_option_value).lower() in ["false"]:
|
||||
config_option_value = False
|
||||
elif str(config_option_value).lower() in ["true"]:
|
||||
config_option_value = True
|
||||
self.conf_default[section][key][config_option] = config_option_value
|
||||
|
||||
def read_ini_config(self, conffilepath):
|
||||
config_handler = configparser.ConfigParser()
|
||||
config_handler.read(conffilepath)
|
||||
for each_section in config_handler.sections():
|
||||
@ -57,7 +164,9 @@ class Config():
|
||||
for (each_key, each_val) in config_handler.items(each_section):
|
||||
if not each_val:
|
||||
each_val = None
|
||||
elif each_val.lower() in ["none", "false"]:
|
||||
elif each_val.lower() in ["none"]:
|
||||
each_val = None
|
||||
elif each_val.lower() in ["false"]:
|
||||
each_val = False
|
||||
elif each_val.lower() in ["true"]:
|
||||
each_val = True
|
||||
@ -69,7 +178,15 @@ class Config():
|
||||
each_val = eval(each_val)
|
||||
elif "," in each_val:
|
||||
each_val = each_val.split(",")
|
||||
self.dict[each_section.lower()][each_key.lower()] = each_val
|
||||
|
||||
import_val = True
|
||||
if each_section in list(self.conf_default.keys()):
|
||||
if each_key in list(self.conf_default[each_section].keys()):
|
||||
if not self.conf_default[each_section][each_key]["config_file"]:
|
||||
import_val = False
|
||||
|
||||
if import_val:
|
||||
self.dict[each_section.lower()][each_key.lower()] = each_val
|
||||
|
||||
def write(self, section, key, value):
|
||||
if section == self.dict["main"]["dictpopname"]:
|
||||
@ -126,95 +243,26 @@ class Config():
|
||||
raise fHDHR.exceptions.ConfigurationError("Invalid EPG Method. Exiting...")
|
||||
self.dict["epg"]["def_method"] = self.dict["epg"]["method"][0]
|
||||
|
||||
# generate UUID here for when we are not using docker
|
||||
if not self.dict["main"]["uuid"]:
|
||||
# from https://pynative.com/python-generate-random-string/
|
||||
# create a string that wouldn't be a real device uuid for
|
||||
self.dict["main"]["uuid"] = ''.join(random.choice("hijklmnopqrstuvwxyz") for i in range(8))
|
||||
self.write('main', 'uuid', self.dict["main"]["uuid"])
|
||||
|
||||
if self.dict["main"]["cache_dir"]:
|
||||
if not pathlib.Path(self.dict["main"]["cache_dir"]).is_dir():
|
||||
raise fHDHR.exceptions.ConfigurationError("Invalid Cache Directory. Exiting...")
|
||||
self.dict["filedir"]["cache_dir"] = pathlib.Path(self.dict["main"]["cache_dir"])
|
||||
cache_dir = self.dict["filedir"]["cache_dir"]
|
||||
self.internal["paths"]["cache_dir"] = pathlib.Path(self.dict["main"]["cache_dir"])
|
||||
cache_dir = self.internal["paths"]["cache_dir"]
|
||||
|
||||
logs_dir = pathlib.Path(cache_dir).joinpath('logs')
|
||||
self.dict["filedir"]["logs_dir"] = logs_dir
|
||||
self.internal["paths"]["logs_dir"] = logs_dir
|
||||
if not logs_dir.is_dir():
|
||||
logs_dir.mkdir()
|
||||
|
||||
self.dict["database"]["path"] = pathlib.Path(cache_dir).joinpath('fhdhr.db')
|
||||
|
||||
for epg_method in self.dict["main"]["valid_epg_methods"]:
|
||||
if epg_method and epg_method != "None":
|
||||
epg_cache_dir = pathlib.Path(cache_dir).joinpath(epg_method)
|
||||
if not epg_cache_dir.is_dir():
|
||||
epg_cache_dir.mkdir()
|
||||
if epg_method not in list(self.dict["filedir"]["epg_cache"].keys()):
|
||||
self.dict["filedir"]["epg_cache"][epg_method] = {}
|
||||
self.dict["filedir"]["epg_cache"][epg_method]["top"] = epg_cache_dir
|
||||
epg_web_cache_dir = pathlib.Path(epg_cache_dir).joinpath("web_cache")
|
||||
if not epg_web_cache_dir.is_dir():
|
||||
epg_web_cache_dir.mkdir()
|
||||
self.dict["filedir"]["epg_cache"][epg_method]["web_cache"] = epg_web_cache_dir
|
||||
self.dict["filedir"]["epg_cache"][epg_method]["epg_json"] = pathlib.Path(epg_cache_dir).joinpath('epg.json')
|
||||
|
||||
if self.dict["fhdhr"]["stream_type"] not in ["direct", "ffmpeg", "vlc"]:
|
||||
raise fHDHR.exceptions.ConfigurationError("Invalid stream type. Exiting...")
|
||||
|
||||
opersystem = platform.system()
|
||||
self.dict["main"]["opersystem"] = opersystem
|
||||
if opersystem in ["Linux", "Darwin"]:
|
||||
# Linux/Mac
|
||||
if os.getuid() == 0 or os.geteuid() == 0:
|
||||
print('Warning: Do not run fHDHR with root privileges.')
|
||||
elif opersystem in ["Windows"]:
|
||||
# Windows
|
||||
if os.environ.get("USERNAME") == "Administrator":
|
||||
print('Warning: Do not run fHDHR as Administrator.')
|
||||
else:
|
||||
print("Uncommon Operating System, use at your own risk.")
|
||||
|
||||
isdocker = is_docker()
|
||||
self.dict["main"]["isdocker"] = isdocker
|
||||
|
||||
if self.dict["fhdhr"]["stream_type"] == "ffmpeg":
|
||||
try:
|
||||
ffmpeg_command = [self.dict["ffmpeg"]["ffmpeg_path"],
|
||||
"-version",
|
||||
"pipe:stdout"
|
||||
]
|
||||
|
||||
ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE)
|
||||
ffmpeg_version = ffmpeg_proc.stdout.read()
|
||||
ffmpeg_proc.terminate()
|
||||
ffmpeg_proc.communicate()
|
||||
ffmpeg_version = ffmpeg_version.decode().split("version ")[1].split(" ")[0]
|
||||
except FileNotFoundError:
|
||||
ffmpeg_version = None
|
||||
self.dict["ffmpeg"]["version"] = ffmpeg_version
|
||||
else:
|
||||
self.dict["ffmpeg"]["version"] = "N/A"
|
||||
|
||||
if self.dict["fhdhr"]["stream_type"] == "vlc":
|
||||
try:
|
||||
vlc_command = [self.dict["vlc"]["vlc_path"],
|
||||
"--version",
|
||||
"pipe:stdout"
|
||||
]
|
||||
|
||||
vlc_proc = subprocess.Popen(vlc_command, stdout=subprocess.PIPE)
|
||||
vlc_version = vlc_proc.stdout.read()
|
||||
vlc_proc.terminate()
|
||||
vlc_proc.communicate()
|
||||
vlc_version = vlc_version.decode().split("version ")[1].split('\n')[0]
|
||||
except FileNotFoundError:
|
||||
vlc_version = None
|
||||
self.dict["vlc"]["version"] = vlc_version
|
||||
else:
|
||||
self.dict["vlc"]["version"] = "N/A"
|
||||
|
||||
if not self.dict["fhdhr"]["discovery_address"] and self.dict["fhdhr"]["address"] != "0.0.0.0":
|
||||
self.dict["fhdhr"]["discovery_address"] = self.dict["fhdhr"]["address"]
|
||||
if not self.dict["fhdhr"]["discovery_address"] or self.dict["fhdhr"]["discovery_address"] == "0.0.0.0":
|
||||
@ -227,7 +275,7 @@ class Config():
|
||||
# Create a custom logger
|
||||
logging.basicConfig(format='%(name)s - %(levelname)s - %(message)s', level=log_level)
|
||||
logger = logging.getLogger('fHDHR')
|
||||
log_file = os.path.join(self.dict["filedir"]["logs_dir"], 'fHDHR.log')
|
||||
log_file = os.path.join(self.internal["paths"]["logs_dir"], 'fHDHR.log')
|
||||
|
||||
# Create handlers
|
||||
# c_handler = logging.StreamHandler()
|
||||
|
||||
@ -104,7 +104,7 @@ class fHDHRdb(object):
|
||||
db_user = self.config.dict["database"]["user"]
|
||||
db_pass = self.config.dict["database"]["pass"]
|
||||
db_host = self.config.dict["database"]["host"]
|
||||
db_port = self.config.dict["database"]["prt"] # Optional
|
||||
db_port = self.config.dict["database"]["port"] # Optional
|
||||
db_name = self.config.dict["database"]["name"] # Optional, depending on DB
|
||||
|
||||
# Ensure we have all our variables defined
|
||||
|
||||
@ -14,8 +14,6 @@ class zap2itEPG():
|
||||
|
||||
self.postalcode = self.fhdhr.config.dict["zap2it"]["postalcode"]
|
||||
|
||||
self.fhdhr.web_cache_dir = self.fhdhr.config.dict["filedir"]["epg_cache"]["zap2it"]["web_cache"]
|
||||
|
||||
def get_location(self):
|
||||
self.fhdhr.logger.warning("Zap2it postalcode not set, attempting to retrieve.")
|
||||
if not self.postalcode:
|
||||
|
||||
@ -35,7 +35,7 @@ class imageHandler():
|
||||
colorBackground = "#228822"
|
||||
colorText = "#717D7E"
|
||||
colorOutline = "#717D7E"
|
||||
fontname = str(self.fhdhr.config.dict["filedir"]["font"])
|
||||
fontname = str(self.fhdhr.config.internal["paths"]["font"])
|
||||
|
||||
font = PIL.ImageFont.truetype(fontname, fontsize)
|
||||
text_width, text_height = self.getSize(message, font)
|
||||
|
||||
@ -42,7 +42,7 @@ class FFMPEG_Stream():
|
||||
|
||||
def ffmpeg_command_assemble(self, stream_args):
|
||||
ffmpeg_command = [
|
||||
self.fhdhr.config.dict["ffmpeg"]["ffmpeg_path"],
|
||||
self.fhdhr.config.dict["ffmpeg"]["path"],
|
||||
"-i", stream_args["channelUri"],
|
||||
]
|
||||
ffmpeg_command.extend(self.ffmpeg_duration(stream_args))
|
||||
|
||||
@ -44,7 +44,7 @@ class VLC_Stream():
|
||||
|
||||
def vlc_command_assemble(self, stream_args):
|
||||
vlc_command = [
|
||||
self.fhdhr.config.dict["vlc"]["vlc_path"],
|
||||
self.fhdhr.config.dict["vlc"]["path"],
|
||||
"-I", "dummy", stream_args["channelUri"],
|
||||
]
|
||||
vlc_command.extend(self.vlc_duration(stream_args))
|
||||
|
||||
@ -13,7 +13,7 @@ class fHDHR_HTTP_Server():
|
||||
def __init__(self, fhdhr):
|
||||
self.fhdhr = fhdhr
|
||||
|
||||
self.template_folder = fhdhr.config.dict["filedir"]["www_templates_dir"]
|
||||
self.template_folder = fhdhr.config.internal["paths"]["www_templates_dir"]
|
||||
|
||||
self.app = Flask("fHDHR", template_folder=self.template_folder)
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
|
||||
from .cluster import Cluster
|
||||
from .settings import Settings
|
||||
from .channels import Channels
|
||||
from .lineup_post import Lineup_Post
|
||||
from .xmltv import xmlTV
|
||||
@ -17,6 +18,7 @@ class fHDHR_API():
|
||||
self.fhdhr = fhdhr
|
||||
|
||||
self.cluster = Cluster(fhdhr)
|
||||
self.settings = Settings(fhdhr)
|
||||
self.channels = Channels(fhdhr)
|
||||
self.xmltv = xmlTV(fhdhr)
|
||||
self.m3u = M3U(fhdhr)
|
||||
|
||||
40
fHDHR/http/api/settings.py
Normal file
40
fHDHR/http/api/settings.py
Normal file
@ -0,0 +1,40 @@
|
||||
from flask import request, redirect
|
||||
import urllib.parse
|
||||
|
||||
|
||||
class Settings():
|
||||
endpoints = ["/api/settings"]
|
||||
endpoint_name = "api_settings"
|
||||
endpoint_methods = ["GET", "POST"]
|
||||
|
||||
def __init__(self, fhdhr):
|
||||
self.fhdhr = fhdhr
|
||||
|
||||
def __call__(self, *args):
|
||||
return self.get(*args)
|
||||
|
||||
def get(self, *args):
|
||||
|
||||
method = request.args.get('method', default="get", type=str)
|
||||
redirect_url = request.args.get('redirect', default=None, type=str)
|
||||
|
||||
if method == "update":
|
||||
config_section = request.form.get('config_section', None)
|
||||
config_name = request.form.get('config_name', None)
|
||||
config_value = request.form.get('config_value', None)
|
||||
|
||||
if not config_section or not config_name or not config_value:
|
||||
if redirect_url:
|
||||
return redirect(redirect_url + "?retmessage=" + urllib.parse.quote("%s Failed" % method))
|
||||
else:
|
||||
return "%s Falied" % method
|
||||
|
||||
if config_section == "origin":
|
||||
config_section = self.fhdhr.config.dict["main"]["dictpopname"]
|
||||
|
||||
self.fhdhr.config.write(config_section, config_name, config_value)
|
||||
|
||||
if redirect_url:
|
||||
return redirect(redirect_url + "?retmessage=" + urllib.parse.quote("%s Success" % method))
|
||||
else:
|
||||
return "%s Success" % method
|
||||
@ -13,6 +13,6 @@ class Favicon_ICO():
|
||||
|
||||
def get(self, *args):
|
||||
|
||||
return send_from_directory(self.fhdhr.config.dict["filedir"]["www_dir"],
|
||||
return send_from_directory(self.fhdhr.config.internal["paths"]["www_dir"],
|
||||
'favicon.ico',
|
||||
mimetype='image/vnd.microsoft.icon')
|
||||
|
||||
@ -13,5 +13,5 @@ class Style_CSS():
|
||||
|
||||
def get(self, *args):
|
||||
|
||||
return send_from_directory(self.fhdhr.config.dict["filedir"]["www_dir"],
|
||||
return send_from_directory(self.fhdhr.config.internal["paths"]["www_dir"],
|
||||
'style.css')
|
||||
|
||||
@ -8,6 +8,7 @@ from .streams_html import Streams_HTML
|
||||
from .version_html import Version_HTML
|
||||
from .guide_html import Guide_HTML
|
||||
from .xmltv_html import xmlTV_HTML
|
||||
from .settings import Settings_HTML
|
||||
|
||||
|
||||
class fHDHR_Pages():
|
||||
@ -16,6 +17,7 @@ class fHDHR_Pages():
|
||||
self.fhdhr = fhdhr
|
||||
|
||||
self.index = Index_HTML(fhdhr)
|
||||
self.settings = Settings_HTML(fhdhr)
|
||||
self.origin = Origin_HTML(fhdhr)
|
||||
self.cluster = Cluster_HTML(fhdhr)
|
||||
self.diagnostics = Diagnostics_HTML(fhdhr)
|
||||
|
||||
@ -17,9 +17,9 @@ class Index_HTML():
|
||||
max_tuners = self.fhdhr.device.tuners.max_tuners
|
||||
|
||||
fhdhr_status_dict = {
|
||||
"Script Directory": str(self.fhdhr.config.dict["filedir"]["script_dir"]),
|
||||
"Script Directory": str(self.fhdhr.config.internal["paths"]["script_dir"]),
|
||||
"Config File": str(self.fhdhr.config.config_file),
|
||||
"Cache Path": str(self.fhdhr.config.dict["filedir"]["cache_dir"]),
|
||||
"Cache Path": str(self.fhdhr.config.internal["paths"]["cache_dir"]),
|
||||
"Total Channels": str(self.fhdhr.device.channels.get_station_total()),
|
||||
"Tuner Usage": ("%s/%s" % (str(tuners_in_use), str(max_tuners))),
|
||||
}
|
||||
|
||||
33
fHDHR/http/pages/settings.py
Normal file
33
fHDHR/http/pages/settings.py
Normal file
@ -0,0 +1,33 @@
|
||||
from flask import request, render_template
|
||||
|
||||
|
||||
class Settings_HTML():
|
||||
endpoints = ["/settings", "/settings.html"]
|
||||
endpoint_name = "settings"
|
||||
|
||||
def __init__(self, fhdhr):
|
||||
self.fhdhr = fhdhr
|
||||
|
||||
def __call__(self, *args):
|
||||
return self.get(*args)
|
||||
|
||||
def get(self, *args):
|
||||
|
||||
web_settings_dict = {}
|
||||
for config_section in list(self.fhdhr.config.conf_default.keys()):
|
||||
web_settings_dict[config_section] = {}
|
||||
|
||||
for config_item in list(self.fhdhr.config.conf_default[config_section].keys()):
|
||||
if self.fhdhr.config.conf_default[config_section][config_item]["config_web"]:
|
||||
real_config_section = config_section
|
||||
if config_section == self.fhdhr.config.dict["main"]["dictpopname"]:
|
||||
real_config_section = "origin"
|
||||
web_settings_dict[config_section][config_item] = {
|
||||
"value": self.fhdhr.config.dict[real_config_section][config_item],
|
||||
"value_default": self.fhdhr.config.conf_default[config_section][config_item]["value"],
|
||||
"hide": self.fhdhr.config.conf_default[config_section][config_item]["config_web_hidden"]
|
||||
}
|
||||
if not len(web_settings_dict[config_section].keys()):
|
||||
del web_settings_dict[config_section]
|
||||
|
||||
return render_template('settings.html', request=request, fhdhr=self.fhdhr, web_settings_dict=web_settings_dict, list=list)
|
||||
@ -17,9 +17,9 @@ class Version_HTML():
|
||||
version_dict = {
|
||||
"fHDHR": self.fhdhr.version,
|
||||
"Python": sys.version,
|
||||
"Operating System": self.fhdhr.config.dict["main"]["opersystem"],
|
||||
"Using Docker": self.fhdhr.config.dict["main"]["isdocker"],
|
||||
"ffmpeg": self.fhdhr.config.dict["ffmpeg"]["version"],
|
||||
"vlc": self.fhdhr.config.dict["vlc"]["version"],
|
||||
"Operating System": self.fhdhr.config.internal["versions"]["opersystem"],
|
||||
"Using Docker": self.fhdhr.config.internal["versions"]["isdocker"],
|
||||
"ffmpeg": self.fhdhr.config.internal["versions"]["ffmpeg"],
|
||||
"vlc": self.fhdhr.config.internal["versions"]["vlc"],
|
||||
}
|
||||
return render_template('version.html', request=request, fhdhr=self.fhdhr, version_dict=version_dict, list=list)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user