settings refactoring

This commit is contained in:
DYefremov
2019-12-22 20:42:29 +03:00
parent 3859c84c0e
commit 5aec42548e
20 changed files with 1414 additions and 1137 deletions

View File

@@ -12,7 +12,7 @@ from urllib.parse import urlencode
from urllib.request import urlopen, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener, install_opener
from app.commons import log
from app.settings import Profile
from app.settings import SettingsType
_BQ_FILES_LIST = ("tv", "radio", # enigma 2
"myservices.xml", "bouquets.xml", "ubouquets.xml") # neutrino
@@ -49,7 +49,7 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print):
with FTP(host=settings.host, user=settings.user, passwd=settings.password) as ftp:
ftp.encoding = "utf-8"
callback("FTP OK.\n")
save_path = settings.data_dir_path
save_path = settings.data_local_path
os.makedirs(os.path.dirname(save_path), exist_ok=True)
files = []
# bouquets
@@ -94,14 +94,14 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print):
def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False,
callback=print, done_callback=None, use_http=False):
profile = settings.profile
data_path = settings.data_dir_path
s_type = settings.setting_type
data_path = settings.data_local_path
host = settings.host
base_url = "http://{}:{}/api/".format(host, settings.http_port)
tn, ht = None, None # telnet, http
try:
if profile is Profile.ENIGMA_2 and use_http:
if s_type is SettingsType.ENIGMA_2 and use_http:
ht = http(settings.http_user, settings.http_password, base_url, callback)
next(ht)
message = ""
@@ -139,7 +139,7 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
if download_type is DownloadType.SATELLITES:
upload_xml(ftp, data_path, sat_xml_path, _SAT_XML_FILE, callback)
if profile is Profile.NEUTRINO_MP and download_type is DownloadType.WEBTV:
if s_type is SettingsType.NEUTRINO_MP and download_type is DownloadType.WEBTV:
upload_xml(ftp, data_path, sat_xml_path, _WEBTV_XML_FILE, callback)
if download_type is DownloadType.BOUQUETS:
@@ -148,7 +148,7 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
if download_type is DownloadType.ALL:
upload_xml(ftp, data_path, sat_xml_path, _SAT_XML_FILE, callback)
if profile is Profile.NEUTRINO_MP:
if s_type is SettingsType.NEUTRINO_MP:
upload_xml(ftp, data_path, sat_xml_path, _WEBTV_XML_FILE, callback)
ftp.cwd(services_path)
@@ -156,11 +156,11 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
upload_files(ftp, data_path, _DATA_FILES_LIST, callback)
if download_type is DownloadType.PICONS:
upload_picons(ftp, settings.picons_dir_path, settings.picons_path, callback)
upload_picons(ftp, settings.picons_local_path, settings.picons_path, callback)
if tn and not use_http:
# resume enigma or restart neutrino
tn.send("init 3" if profile is Profile.ENIGMA_2 else "init 6")
tn.send("init 3" if s_type is SettingsType.ENIGMA_2 else "init 6")
elif ht and use_http:
if download_type is DownloadType.BOUQUETS:
ht.send(base_url + "/servicelistreload?mode=2")

View File

@@ -1,5 +1,5 @@
from app.commons import run_task
from app.settings import Profile
from app.settings import SettingsType
from .ecommons import Service, Satellite, Transponder, Bouquet, Bouquets, is_transponder_valid
from .enigma.blacklist import get_blacklist, write_blacklist
from .enigma.bouquets import get_bouquets as get_enigma_bouquets, write_bouquets as write_enigma_bouquets, to_bouquet_id
@@ -10,33 +10,33 @@ from .neutrino.services import get_services as get_neutrino_services, write_serv
from .satxml import get_satellites, write_satellites
def get_services(data_path, profile, format_version):
if profile is Profile.ENIGMA_2:
def get_services(data_path, s_type, format_version):
if s_type is SettingsType.ENIGMA_2:
return get_enigma_services(data_path, format_version)
elif profile is Profile.NEUTRINO_MP:
elif s_type is SettingsType.NEUTRINO_MP:
return get_neutrino_services(data_path)
@run_task
def write_services(path, channels, profile, format_version):
if profile is Profile.ENIGMA_2:
def write_services(path, channels, s_type, format_version):
if s_type is SettingsType.ENIGMA_2:
write_enigma_services(path, channels, format_version)
elif profile is Profile.NEUTRINO_MP:
elif s_type is SettingsType.NEUTRINO_MP:
write_neutrino_services(path, channels)
def get_bouquets(path, profile):
if profile is Profile.ENIGMA_2:
def get_bouquets(path, s_type):
if s_type is SettingsType.ENIGMA_2:
return get_enigma_bouquets(path)
elif profile is Profile.NEUTRINO_MP:
elif s_type is SettingsType.NEUTRINO_MP:
return get_neutrino_bouquets(path)
@run_task
def write_bouquets(path, bouquets, profile):
if profile is Profile.ENIGMA_2:
def write_bouquets(path, bouquets, s_type):
if s_type is SettingsType.ENIGMA_2:
write_enigma_bouquets(path, bouquets)
elif profile is Profile.NEUTRINO_MP:
elif s_type is SettingsType.NEUTRINO_MP:
write_neutrino_bouquets(path, bouquets)

View File

@@ -3,7 +3,7 @@ import re
import urllib.request
from enum import Enum
from app.settings import Profile
from app.settings import SettingsType
from app.ui.uicommons import IPTV_ICON
from .ecommons import BqServiceType, Service
@@ -20,18 +20,18 @@ class StreamType(Enum):
NONE_REC_2 = "5002"
def parse_m3u(path, profile):
def parse_m3u(path, s_type):
with open(path) as file:
aggr = [None] * 10
services = []
groups = set()
counter = 0
name = None
for line in file.readlines():
if line.startswith("#EXTINF"):
name = line[1 + line.index(","):].strip()
elif line.startswith("#EXTGRP") and profile is Profile.ENIGMA_2:
elif line.startswith("#EXTGRP") and s_type is SettingsType.ENIGMA_2:
grp_name = line.strip("#EXTGRP:").strip()
if grp_name not in groups:
groups.add(grp_name)
@@ -41,7 +41,7 @@ def parse_m3u(path, profile):
services.append(mr)
elif not line.startswith("#"):
url = line.strip()
fav_id = get_fav_id(url, name, profile)
fav_id = get_fav_id(url, name, s_type)
if name and url:
srv = Service(None, None, IPTV_ICON, name, *aggr[0:3], BqServiceType.IPTV.name, *aggr, fav_id, None)
services.append(srv)
@@ -49,8 +49,8 @@ def parse_m3u(path, profile):
return services
def export_to_m3u(path, bouquet, profile):
pattern = re.compile(".*:(http.*):.*") if profile is Profile.ENIGMA_2 else re.compile("(http.*?)::::.*")
def export_to_m3u(path, bouquet, s_type):
pattern = re.compile(".*:(http.*):.*") if s_type is SettingsType.ENIGMA_2 else re.compile("(http.*?)::::.*")
lines = ["#EXTM3U\n"]
current_grp = None
@@ -72,13 +72,13 @@ def export_to_m3u(path, bouquet, profile):
file.writelines(lines)
def get_fav_id(url, service_name, profile):
def get_fav_id(url, service_name, s_type):
""" Returns fav id depending on the profile. """
if profile is Profile.ENIGMA_2:
if s_type is SettingsType.ENIGMA_2:
url = urllib.request.quote(url)
stream_type = StreamType.NONE_TS.value
return ENIGMA2_FAV_ID_FORMAT.format(stream_type, 1, 0, 0, 0, 0, url, service_name, service_name, None)
elif profile is Profile.NEUTRINO_MP:
elif s_type is SettingsType.NEUTRINO_MP:
return NEUTRINO_FAV_ID_FORMAT.format(url, "", 0, None, None, None, None, "", "", 1)

View File

@@ -2,7 +2,7 @@ import json
import os
from pprint import pformat
from textwrap import dedent
from enum import Enum
from enum import Enum, IntEnum
from pathlib import Path
CONFIG_PATH = str(Path.home()) + "/.config/demon-editor/"
@@ -10,19 +10,85 @@ CONFIG_FILE = CONFIG_PATH + "config.json"
DATA_PATH = "data/"
class Profile(Enum):
class Defaults(Enum):
""" Default program settings """
DEFAULT_PROFILE = "default"
BACKUP_BEFORE_DOWNLOADING = True
BACKUP_BEFORE_SAVE = True
V5_SUPPORT = False
HTTP_API_SUPPORT = False
ENABLE_YT_DL = False
ENABLE_SEND_TO = False
USE_COLORS = True
NEW_COLOR = "rgb(255,230,204)"
EXTRA_COLOR = "rgb(179,230,204)"
FAV_CLICK_MODE = 0
def get_default_settings():
return {
"version": 1,
"default_profile": Defaults.DEFAULT_PROFILE.value,
"profiles": {"default": SettingsType.ENIGMA_2.get_default_settings()},
"v5_support": Defaults.V5_SUPPORT.value,
"http_api_support": Defaults.HTTP_API_SUPPORT.value,
"enable_yt_dl": Defaults.ENABLE_YT_DL.value,
"enable_send_to": Defaults.ENABLE_SEND_TO.value,
"use_colors": Defaults.USE_COLORS.value,
"new_color": Defaults.NEW_COLOR.value,
"extra_color": Defaults.EXTRA_COLOR.value,
"fav_click_mode": Defaults.FAV_CLICK_MODE.value
}
class SettingsType(IntEnum):
""" Profiles for settings """
ENIGMA_2 = "0"
NEUTRINO_MP = "1"
ENIGMA_2 = 0
NEUTRINO_MP = 1
def get_default_settings(self):
""" Returns default settings for current type """
if self is self.ENIGMA_2:
return {"setting_type": self,
"host": "127.0.0.1", "port": "21", "user": "root", "password": "root", "timeout": 5,
"http_user": "root", "http_password": "", "http_port": "80", "http_timeout": 5,
"telnet_user": "root", "telnet_password": "", "telnet_port": "23", "telnet_timeout": 5,
"services_path": "/etc/enigma2/", "user_bouquet_path": "/etc/enigma2/",
"satellites_xml_path": "/etc/tuxbox/", "data_local_path": DATA_PATH + "enigma2/",
"picons_path": "/usr/share/enigma2/picon",
"picons_local_path": DATA_PATH + "enigma2/picons/",
"backup_local_path": DATA_PATH + "enigma2/backup/"}
elif self is self.NEUTRINO_MP:
return {"setting_type": self,
"host": "127.0.0.1", "port": "21", "user": "root", "password": "root", "timeout": 5,
"http_user": "", "http_password": "", "http_port": "80", "http_timeout": 2,
"telnet_user": "root", "telnet_password": "", "telnet_port": "23", "telnet_timeout": 1,
"services_path": "/var/tuxbox/config/zapit/", "user_bouquet_path": "/var/tuxbox/config/zapit/",
"satellites_xml_path": "/var/tuxbox/config/", "data_local_path": DATA_PATH + "neutrino/",
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/",
"picons_local_path": DATA_PATH + "neutrino/picons/",
"backup_local_path": DATA_PATH + "neutrino/backup/"}
class SettingsException(Exception):
pass
class Settings:
__INSTANCE = None
__VERSION = 1
def __init__(self):
self._config = get_config()
self._current_profile = Profile(self._config.get("profile"))
self._current_profile_options = self._config.get(self._current_profile.value)
settings = get_settings()
if self.__VERSION > settings.get("version", 0):
write_settings(get_default_settings())
raise SettingsException("Outdated version of the settings format!")
self._settings = settings
self._current_profile = self._settings.get("default_profile", "default")
self._profiles = self._settings.get("profiles", {"default": SettingsType.ENIGMA_2.get_default_settings()})
self._cp_settings = self._profiles.get(self._current_profile) # Current profile settings
def __str__(self):
return dedent(""" Current profile: {}
@@ -31,8 +97,8 @@ class Settings:
Full config:
{}
""").format(self._current_profile,
pformat(self._current_profile_options),
pformat(self._config))
pformat(self._cp_settings),
pformat(self._settings))
@classmethod
def get_instance(cls):
@@ -41,325 +107,296 @@ class Settings:
return cls.__INSTANCE
def save(self):
write_config(self._config)
write_settings(self._settings)
def reset(self, force_write=False):
def_settings = get_default_settings()
for p in Profile:
current = self._config.get(p.value)
default = def_settings.get(p.value)
for k in default:
current[k] = default.get(k)
for k, v in self.setting_type.get_default_settings().items():
self._cp_settings[k] = v
if force_write:
write_config(get_default_settings())
self.save()
def get_default(self, p_name):
""" Returns default value for current settings type """
return self.setting_type.get_default_settings().get(p_name)
def add(self, name, value):
""" Adds extra options """
self._config[name] = value
self._settings[name] = value
def get(self, name):
""" Returns extra options """
return self._config.get(name, None)
def get_default(self, name):
""" Returns default value of the option """
return get_default_settings().get(self._current_profile.value).get(name)
""" Returns extra options or None """
return self._settings.get(name, None)
@property
def presets(self):
raise NotImplementedError
def profiles(self):
return self._profiles
@presets.setter
def presets(self, name):
raise NotImplementedError
@profiles.setter
def profiles(self, ps):
self._profiles = ps
self._settings["profiles"] = self._profiles
@property
def profile(self):
return self._current_profile
def setting_type(self):
return SettingsType(self._cp_settings.get("setting_type", SettingsType.ENIGMA_2.value))
@profile.setter
def profile(self, prf):
self._current_profile = prf
self._config["profile"] = prf.value
self._current_profile_options = self._config.get(prf.value)
@setting_type.setter
def setting_type(self, s_type):
self._cp_settings["setting_type"] = s_type
for k, v in s_type.get_default_settings().items():
self._cp_settings[k] = v
@property
def host(self):
return self._current_profile_options.get("host", self.get_default("host"))
return self._cp_settings.get("host", self.get_default("host"))
@host.setter
def host(self, value):
self._current_profile_options["host"] = value
self._cp_settings["host"] = value
@property
def port(self):
return self._current_profile_options.get("port", self.get_default("port"))
return self._cp_settings.get("port", self.get_default("port"))
@port.setter
def port(self, value):
self._current_profile_options["port"] = value
self._cp_settings["port"] = value
@property
def user(self):
return self._current_profile_options.get("user", self.get_default("user"))
return self._cp_settings.get("user", self.get_default("user"))
@user.setter
def user(self, value):
self._current_profile_options["user"] = value
self._cp_settings["user"] = value
@property
def password(self):
return self._current_profile_options.get("password", self.get_default("password"))
return self._cp_settings.get("password", self.get_default("password"))
@password.setter
def password(self, value):
self._current_profile_options["password"] = value
self._cp_settings["password"] = value
@property
def http_user(self):
return self._current_profile_options.get("http_user", self.get_default("http_user"))
return self._cp_settings.get("http_user", self.get_default("http_user"))
@http_user.setter
def http_user(self, value):
self._current_profile_options["http_user"] = value
self._cp_settings["http_user"] = value
@property
def http_password(self):
return self._current_profile_options.get("http_password", self.get_default("http_password"))
return self._cp_settings.get("http_password", self.get_default("http_password"))
@http_password.setter
def http_password(self, value):
self._current_profile_options["http_password"] = value
self._cp_settings["http_password"] = value
@property
def http_port(self):
return self._current_profile_options.get("http_port", self.get_default("http_port"))
return self._cp_settings.get("http_port", self.get_default("http_port"))
@http_port.setter
def http_port(self, value):
self._current_profile_options["http_port"] = value
self._cp_settings["http_port"] = value
@property
def http_timeout(self):
return self._current_profile_options.get("http_timeout", self.get_default("http_timeout"))
return self._cp_settings.get("http_timeout", self.get_default("http_timeout"))
@http_timeout.setter
def http_timeout(self, value):
self._current_profile_options["http_timeout"] = value
self._cp_settings["http_timeout"] = value
@property
def telnet_user(self):
return self._current_profile_options.get("telnet_user", self.get_default("telnet_user"))
return self._cp_settings.get("telnet_user", self.get_default("telnet_user"))
@telnet_user.setter
def telnet_user(self, value):
self._current_profile_options["telnet_user"] = value
self._cp_settings["telnet_user"] = value
@property
def telnet_password(self):
return self._current_profile_options.get("telnet_password", self.get_default("telnet_password"))
return self._cp_settings.get("telnet_password", self.get_default("telnet_password"))
@telnet_password.setter
def telnet_password(self, value):
self._current_profile_options["telnet_password"] = value
self._cp_settings["telnet_password"] = value
@property
def telnet_port(self):
return self._current_profile_options.get("telnet_port", self.get_default("telnet_port"))
return self._cp_settings.get("telnet_port", self.get_default("telnet_port"))
@telnet_port.setter
def telnet_port(self, value):
self._current_profile_options["telnet_port"] = value
self._cp_settings["telnet_port"] = value
@property
def telnet_timeout(self):
return self._current_profile_options.get("telnet_timeout", self.get_default("telnet_timeout"))
return self._cp_settings.get("telnet_timeout", self.get_default("telnet_timeout"))
@telnet_timeout.setter
def telnet_timeout(self, value):
self._current_profile_options["telnet_timeout"] = value
self._cp_settings["telnet_timeout"] = value
@property
def services_path(self):
return self._current_profile_options.get("services_path", self.get_default("services_path"))
return self._cp_settings.get("services_path", self.get_default("services_path"))
@services_path.setter
def services_path(self, value):
self._current_profile_options["services_path"] = value
self._cp_settings["services_path"] = value
@property
def user_bouquet_path(self):
return self._current_profile_options.get("user_bouquet_path", self.get_default("user_bouquet_path"))
return self._cp_settings.get("user_bouquet_path", self.get_default("user_bouquet_path"))
@user_bouquet_path.setter
def user_bouquet_path(self, value):
self._current_profile_options["user_bouquet_path"] = value
self._cp_settings["user_bouquet_path"] = value
@property
def satellites_xml_path(self):
return self._current_profile_options.get("satellites_xml_path", self.get_default("satellites_xml_path"))
return self._cp_settings.get("satellites_xml_path", self.get_default("satellites_xml_path"))
@satellites_xml_path.setter
def satellites_xml_path(self, value):
self._current_profile_options["satellites_xml_path"] = value
self._cp_settings["satellites_xml_path"] = value
@property
def data_dir_path(self):
return self._current_profile_options.get("data_dir_path", self.get_default("data_dir_path"))
def data_local_path(self):
return self._cp_settings.get("data_local_path", self.get_default("data_local_path"))
@data_dir_path.setter
def data_dir_path(self, value):
self._current_profile_options["data_dir_path"] = value
@data_local_path.setter
def data_local_path(self, value):
self._cp_settings["data_local_path"] = value
@property
def picons_path(self):
return self._current_profile_options.get("picons_path", self.get_default("picons_path"))
return self._cp_settings.get("picons_path", self.get_default("picons_path"))
@picons_path.setter
def picons_path(self, value):
self._current_profile_options["picons_path"] = value
self._cp_settings["picons_path"] = value
@property
def picons_dir_path(self):
return self._current_profile_options.get("picons_dir_path", self.get_default("picons_dir_path"))
def picons_local_path(self):
return self._cp_settings.get("picons_local_path", self.get_default("picons_local_path"))
@picons_dir_path.setter
def picons_dir_path(self, value):
self._current_profile_options["picons_dir_path"] = value
@picons_local_path.setter
def picons_local_path(self, value):
self._cp_settings["picons_local_path"] = value
@property
def backup_dir_path(self):
return self._current_profile_options.get("backup_dir_path", self.get_default("backup_dir_path"))
def backup_local_path(self):
return self._cp_settings.get("backup_local_path", self.get_default("backup_local_path"))
@backup_dir_path.setter
def backup_dir_path(self, value):
self._current_profile_options["backup_dir_path"] = value
@backup_local_path.setter
def backup_local_path(self, value):
self._cp_settings["backup_local_path"] = value
# ***** Program settings *****
@property
def backup_before_save(self):
return self._current_profile_options.get("backup_before_save", self.get_default("backup_before_save"))
return self._settings.get("backup_before_save", Defaults.BACKUP_BEFORE_SAVE.value)
@backup_before_save.setter
def backup_before_save(self, value):
self._current_profile_options["backup_before_save"] = value
self._settings["backup_before_save"] = value
@property
def backup_before_downloading(self):
return self._current_profile_options.get("backup_before_downloading",
self.get_default("backup_before_downloading"))
return self._settings.get("backup_before_downloading", Defaults.BACKUP_BEFORE_DOWNLOADING.value)
@backup_before_downloading.setter
def backup_before_downloading(self, value):
self._current_profile_options["backup_before_downloading"] = value
self._settings["backup_before_downloading"] = value
@property
def v5_support(self):
return self._current_profile_options.get("v5_support", self.get_default("v5_support"))
return self._settings.get("v5_support", Defaults.V5_SUPPORT.value)
@v5_support.setter
def v5_support(self, value):
self._current_profile_options["v5_support"] = value
self._settings["v5_support"] = value
@property
def http_api_support(self):
return self._current_profile_options.get("http_api_support", self.get_default("http_api_support"))
return self._settings.get("http_api_support", Defaults.HTTP_API_SUPPORT.value)
@http_api_support.setter
def http_api_support(self, value):
self._current_profile_options["http_api_support"] = value
self._settings["http_api_support"] = value
@property
def enable_yt_dl(self):
return self._current_profile_options.get("enable_yt_dl", self.get_default("enable_yt_dl"))
return self._settings.get("enable_yt_dl", Defaults.ENABLE_YT_DL.value)
@enable_yt_dl.setter
def enable_yt_dl(self, value):
self._current_profile_options["enable_yt_dl"] = value
self._settings["enable_yt_dl"] = value
@property
def enable_send_to(self):
return self._current_profile_options.get("enable_send_to", self.get_default("enable_send_to"))
return self._settings.get("enable_send_to", Defaults.ENABLE_SEND_TO.value)
@enable_send_to.setter
def enable_send_to(self, value):
self._current_profile_options["enable_send_to"] = value
self._settings["enable_send_to"] = value
@property
def use_colors(self):
return self._current_profile_options.get("use_colors", self.get_default("use_colors"))
return self._settings.get("use_colors", Defaults.USE_COLORS.value)
@use_colors.setter
def use_colors(self, value):
self._current_profile_options["use_colors"] = value
self._settings["use_colors"] = value
@property
def new_color(self):
return self._current_profile_options.get("new_color", self.get_default("new_color"))
return self._settings.get("new_color", Defaults.NEW_COLOR.value)
@new_color.setter
def new_color(self, value):
self._current_profile_options["new_color"] = value
self._settings["new_color"] = value
@property
def extra_color(self):
return self._current_profile_options.get("extra_color", self.get_default("extra_color"))
return self._settings.get("extra_color", Defaults.EXTRA_COLOR.value)
@extra_color.setter
def extra_color(self, value):
self._current_profile_options["extra_color"] = value
self._settings["extra_color"] = value
@property
def fav_click_mode(self):
return self._current_profile_options.get("fav_click_mode", self.get_default("fav_click_mode"))
return self._settings.get("fav_click_mode", Defaults.FAV_CLICK_MODE.value)
@fav_click_mode.setter
def fav_click_mode(self, value):
self._current_profile_options["fav_click_mode"] = value
self._settings["fav_click_mode"] = value
def get_config():
def get_settings():
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True) # create dir if not exist
os.makedirs(os.path.dirname(DATA_PATH), exist_ok=True)
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
write_config(get_default_settings())
write_settings(get_default_settings())
with open(CONFIG_FILE, "r") as config_file:
return json.load(config_file)
def write_config(config):
def write_settings(config):
with open(CONFIG_FILE, "w") as config_file:
json.dump(config, config_file, indent=" ")
def get_default_settings():
return {
Profile.ENIGMA_2.value: {
"host": "127.0.0.1", "port": "21", "user": "root", "password": "root",
"http_user": "root", "http_password": "", "http_port": "80", "http_timeout": 5,
"telnet_user": "root", "telnet_password": "", "telnet_port": "23", "telnet_timeout": 5,
"services_path": "/etc/enigma2/", "user_bouquet_path": "/etc/enigma2/",
"satellites_xml_path": "/etc/tuxbox/", "data_dir_path": DATA_PATH + "enigma2/",
"picons_path": "/usr/share/enigma2/picon", "picons_dir_path": DATA_PATH + "enigma2/picons/",
"backup_dir_path": DATA_PATH + "enigma2/backup/",
"backup_before_save": True, "backup_before_downloading": True,
"v5_support": False, "http_api_support": False, "enable_yt_dl": False, "enable_send_to": False,
"use_colors": True, "new_color": "rgb(255,230,204)", "extra_color": "rgb(179,230,204)",
"fav_click_mode": 0},
Profile.NEUTRINO_MP.value: {
"host": "127.0.0.1", "port": "21", "user": "root", "password": "root",
"http_user": "", "http_password": "", "http_port": "80", "http_timeout": 2,
"telnet_user": "root", "telnet_password": "", "telnet_port": "23", "telnet_timeout": 1,
"services_path": "/var/tuxbox/config/zapit/", "user_bouquet_path": "/var/tuxbox/config/zapit/",
"satellites_xml_path": "/var/tuxbox/config/", "data_dir_path": DATA_PATH + "neutrino/",
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/", "picons_dir_path": DATA_PATH + "neutrino/picons/",
"backup_dir_path": DATA_PATH + "neutrino/backup/",
"backup_before_save": True, "backup_before_downloading": True,
"fav_click_mode": 0},
"profile": Profile.ENIGMA_2.value}
if __name__ == "__main__":
pass

View File

@@ -7,7 +7,7 @@ from collections import namedtuple
from html.parser import HTMLParser
from app.commons import run_task
from app.settings import Profile
from app.settings import SettingsType
_ENIGMA2_PICON_KEY = "{:X}:{:X}:{}"
_NEUTRINO_PICON_KEY = "{:x}{:04x}{:04x}.png"
@@ -79,7 +79,7 @@ class PiconsParser(HTMLParser):
pass
@staticmethod
def parse(open_path, picons_path, tmp_path, provider, picon_ids, profile=Profile.ENIGMA_2):
def parse(open_path, picons_path, tmp_path, provider, picon_ids, s_type=SettingsType.ENIGMA_2):
with open(open_path, encoding="utf-8", errors="replace") as f:
on_id, pos, ssid, single = provider.on_id, provider.pos, provider.ssid, provider.single
neg_pos = pos.endswith("W")
@@ -100,7 +100,7 @@ class PiconsParser(HTMLParser):
namespace = "{:X}{:X}".format(int(pos), int(freq))
else:
namespace = "{:X}0000".format(int(pos))
name = PiconsParser.format(ssid if single else p.ssid, on_id, namespace, picon_ids, profile)
name = PiconsParser.format(ssid if single else p.ssid, on_id, namespace, picon_ids, s_type)
p_name = picons_path + (name if name else os.path.basename(p.ref))
shutil.copyfile(tmp_path + "www.lyngsat.com/" + p.ref.lstrip("."), p_name)
except (TypeError, ValueError) as e:
@@ -109,10 +109,10 @@ class PiconsParser(HTMLParser):
print(msg)
@staticmethod
def format(ssid, on_id, namespace, picon_ids, profile: Profile):
if profile is Profile.ENIGMA_2:
def format(ssid, on_id, namespace, picon_ids, s_type):
if s_type is SettingsType.ENIGMA_2:
return picon_ids.get(_ENIGMA2_PICON_KEY.format(int(ssid), int(on_id), namespace), None)
elif profile is Profile.NEUTRINO_MP:
elif s_type is SettingsType.NEUTRINO_MP:
tr_id = int(ssid[:-2] if len(ssid) < 4 else ssid[:2])
return _NEUTRINO_PICON_KEY.format(tr_id, int(on_id), int(ssid))
else:
@@ -249,12 +249,12 @@ def parse_providers(open_path):
@run_task
def convert_to(src_path, dest_path, profile, callback, done_callback):
def convert_to(src_path, dest_path, s_type, callback, done_callback):
""" Converts names format of picons.
Copies resulting files from src to dest and writes state to callback.
"""
pattern = "/*_0_0_0.png" if profile is Profile.ENIGMA_2 else "/*.png"
pattern = "/*_0_0_0.png" if s_type is SettingsType.ENIGMA_2 else "/*.png"
for file in glob.glob(src_path + pattern):
base_name = os.path.basename(file)
pic_data = base_name.rstrip(".png").split("_")

View File

@@ -7,7 +7,7 @@ from datetime import datetime
from enum import Enum
from app.commons import run_idle
from app.settings import Profile
from app.settings import SettingsType
from app.ui.dialogs import show_dialog, DialogType
from app.ui.main_helper import append_text_to_tview
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey
@@ -36,9 +36,9 @@ class BackupDialog:
builder.connect_signals(handlers)
self._settings = settings
self._profile = settings.profile
self._data_path = self._settings.data_dir_path
self._backup_path = self._settings.backup_dir_path or self._data_path + "backup/"
self._s_type = settings.setting_type
self._data_path = self._settings.data_local_path
self._backup_path = self._settings.backup_local_path or self._data_path + "backup/"
self._open_data_callback = callback
self._dialog_window = builder.get_object("dialog_window")
self._dialog_window.set_transient_for(transient)
@@ -152,7 +152,7 @@ class BackupDialog:
shutil.unpack_archive(full_file_name, self._data_path)
elif restore_type is RestoreType.BOUQUETS:
tmp_dir = tempfile.gettempdir() + "/" + file_name
cond = (".tv", ".radio") if self._profile is Profile.ENIGMA_2 else "bouquets.xml"
cond = (".tv", ".radio") if self._s_type is SettingsType.ENIGMA_2 else "bouquets.xml"
shutil.unpack_archive(full_file_name, tmp_dir)
for file in filter(lambda f: f.endswith(cond), os.listdir(self._data_path)):
os.remove(os.path.join(self._data_path, file))

View File

@@ -101,7 +101,7 @@ def get_file_chooser_dialog(transient, text, settings, action_type, file_filter)
if file_filter is not None:
dialog.add_filter(file_filter)
path = settings.data_dir_path
path = settings.data_local_path
dialog.set_current_folder(path)
response = dialog.run()
if response == Gtk.ResponseType.OK:

View File

@@ -2,7 +2,7 @@ from gi.repository import GLib
from app.commons import run_idle, run_task
from app.connections import download_data, DownloadType, upload_data
from app.settings import Profile
from app.settings import SettingsType
from app.ui.backup import backup_data, restore_data
from app.ui.main_helper import append_text_to_tview
from app.ui.settings_dialog import show_settings_dialog
@@ -12,7 +12,7 @@ from .dialogs import show_dialog, DialogType, get_message
class DownloadDialog:
def __init__(self, transient, settings, open_data_callback, update_settings_callback):
self._profile = settings.profile
self._s_type = settings.setting_type
self._settings = settings
self._open_data_callback = open_data_callback
self._update_settings_callback = update_settings_callback
@@ -59,8 +59,8 @@ class DownloadDialog:
def init_settings(self):
self._host_entry.set_text(self._settings.host)
self._data_path_entry.set_text(self._settings.data_dir_path)
is_enigma = self._profile is Profile.ENIGMA_2
self._data_path_entry.set_text(self._settings.data_local_path)
is_enigma = self._s_type is SettingsType.ENIGMA_2
self._webtv_radio_button.set_visible(not is_enigma)
self._http_radio_button.set_visible(is_enigma)
self._use_http_box.set_visible(is_enigma)
@@ -111,7 +111,7 @@ class DownloadDialog:
def on_preferences(self, item):
response = show_settings_dialog(self._dialog_window, self._settings)
if response != Gtk.ResponseType.CANCEL:
self._profile = self._settings.profile
self._s_type = self._settings.setting_type
self.init_settings()
gen = self._update_settings_callback()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
@@ -134,8 +134,8 @@ class DownloadDialog:
try:
if download:
if backup and d_type is not DownloadType.SATELLITES:
data_path = self._settings.data_dir_path or self._data_path_entry.get_text()
backup_path = self._settings.backup_dir_path or data_path + "backup/"
data_path = self._settings.data_local_path or self._data_path_entry.get_text()
backup_path = self._settings.backup_local_path or data_path + "backup/"
backup_src = backup_data(data_path, backup_path, d_type is DownloadType.ALL)
download_data(settings=self._settings, download_type=d_type, callback=self.append_output)
else:

View File

@@ -483,7 +483,7 @@ class EpgDialog:
# ***************** Options *********************#
def init_options(self):
epg_dat_path = self._settings.data_dir_path + "epg/"
epg_dat_path = self._settings.data_local_path + "epg/"
self._epg_dat_path_entry.set_text(epg_dat_path)
default_epg_data_stb_path = "/etc/enigma2"
epg_options = self._settings.get("epg_options")

View File

@@ -6,7 +6,7 @@ from app.eparser import get_bouquets, get_services
from app.eparser.ecommons import BqType, BqServiceType, Bouquet
from app.eparser.enigma.bouquets import get_bouquet
from app.eparser.neutrino.bouquets import parse_webtv, parse_bouquets as get_neutrino_bouquets
from app.settings import Profile
from app.settings import SettingsType
from app.ui.dialogs import show_dialog, DialogType, get_chooser_dialog, get_message
from app.ui.main_helper import on_popup_menu
from .uicommons import Gtk, UI_RESOURCES_PATH, KeyboardKey, Column
@@ -17,12 +17,12 @@ def import_bouquet(transient, model, path, settings, services, appender):
itr = model.get_iter(path)
bq_type = BqType(model.get(itr, Column.BQ_TYPE)[0])
pattern, f_pattern = None, None
profile = settings.profile
profile = settings.setting_type
if profile is Profile.ENIGMA_2:
if profile is SettingsType.ENIGMA_2:
pattern = ".{}".format(bq_type.value)
f_pattern = "userbouquet.*{}".format(pattern)
elif profile is Profile.NEUTRINO_MP:
elif profile is SettingsType.NEUTRINO_MP:
pattern = "webtv.xml" if bq_type is BqType.WEBTV else "bouquets.xml"
f_pattern = "bouquets.xml"
if bq_type is BqType.TV:
@@ -38,7 +38,7 @@ def import_bouquet(transient, model, path, settings, services, appender):
show_dialog(DialogType.ERROR, transient, text="No bouquet file is selected!")
return
if profile is Profile.ENIGMA_2:
if profile is SettingsType.ENIGMA_2:
bq = get_enigma2_bouquet(file_path)
imported = list(filter(lambda x: x.data in services or x.type is BqServiceType.IPTV, bq.services))
@@ -51,7 +51,7 @@ def import_bouquet(transient, model, path, settings, services, appender):
else:
p_itr = model.iter_parent(itr)
appender(bq, p_itr) if p_itr else appender(bq, itr)
elif profile is Profile.NEUTRINO_MP:
elif profile is SettingsType.NEUTRINO_MP:
if bq_type is BqType.WEBTV:
bqs = parse_webtv(file_path, "WEBTV", bq_type.value)
else:
@@ -90,7 +90,7 @@ class ImportDialog:
self._services = {}
self._service_ids = service_ids
self._append = appender
self._profile = settings.profile
self._profile = settings.setting_type
self._settings = settings
self._bouquets = bouquets
@@ -125,7 +125,7 @@ class ImportDialog:
self._main_model.append((bq.name, bq.type, True))
self._bq_services[(bq.name, bq.type)] = bq.services
# Note! Getting default format ver. 4
services = get_services(path, self._profile, 4 if self._profile is Profile.ENIGMA_2 else 0)
services = get_services(path, self._profile, 4 if self._profile is SettingsType.ENIGMA_2 else 0)
for srv in services:
self._services[srv.fav_id] = srv
except FileNotFoundError as e:

View File

@@ -13,7 +13,7 @@ from gi.repository import GLib
from app.commons import run_idle, run_task, log
from app.eparser.ecommons import BqServiceType, Service
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT, get_fav_id, MARKER_FORMAT
from app.settings import Profile
from app.settings import SettingsType
from app.tools.yt import YouTube, PlayListParser
from .dialogs import Action, show_dialog, DialogType, get_dialogs_string, get_message
from .main_helper import get_base_model, get_iptv_url, on_popup_menu
@@ -61,7 +61,7 @@ def get_yt_icon(icon_name, size=24):
class IptvDialog:
def __init__(self, transient, view, services, bouquet, profile=Profile.ENIGMA_2, action=Action.ADD):
def __init__(self, transient, view, services, bouquet, profile=SettingsType.ENIGMA_2, action=Action.ADD):
handlers = {"on_response": self.on_response,
"on_entry_changed": self.on_entry_changed,
"on_url_changed": self.on_url_changed,
@@ -109,7 +109,7 @@ class IptvDialog:
for el in self._digit_elems:
el.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
if profile is Profile.NEUTRINO_MP:
if profile is SettingsType.NEUTRINO_MP:
builder.get_object("iptv_dialog_ts_data_frame").set_visible(False)
builder.get_object("iptv_type_label").set_visible(False)
builder.get_object("reference_entry").set_visible(False)
@@ -122,7 +122,7 @@ class IptvDialog:
if self._action is Action.ADD:
self._save_button.set_visible(False)
self._add_button.set_visible(True)
if self._profile is Profile.ENIGMA_2:
if self._profile is SettingsType.ENIGMA_2:
self._update_reference_entry()
self._stream_type_combobox.set_active(1)
elif self._action is Action.EDIT:
@@ -147,13 +147,13 @@ class IptvDialog:
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
self.save_enigma2_data() if self._profile is Profile.ENIGMA_2 else self.save_neutrino_data()
self.save_enigma2_data() if self._profile is SettingsType.ENIGMA_2 else self.save_neutrino_data()
self._dialog.destroy()
def init_data(self, srv):
name, fav_id = srv[2], srv[7]
self._name_entry.set_text(name)
self.init_enigma2_data(fav_id) if self._profile is Profile.ENIGMA_2 else self.init_neutrino_data(fav_id)
self.init_enigma2_data(fav_id) if self._profile is SettingsType.ENIGMA_2 else self.init_neutrino_data(fav_id)
def init_enigma2_data(self, fav_id):
data, sep, desc = fav_id.partition("#DESCRIPTION")
@@ -190,7 +190,7 @@ class IptvDialog:
self._description_entry.set_text(data[1])
def _update_reference_entry(self):
if self._profile is Profile.ENIGMA_2:
if self._profile is SettingsType.ENIGMA_2:
self._reference_entry.set_text(_ENIGMA2_REFERENCE.format(self.get_type(),
self._srv_type_entry.get_text(),
int(self._sid_entry.get_text()),
@@ -505,7 +505,7 @@ class IptvListConfigurationDialog:
show_dialog(DialogType.ERROR, self._dialog, "Error. Verify the data!")
return
if self._profile is Profile.ENIGMA_2:
if self._profile is SettingsType.ENIGMA_2:
reset = self._reset_to_default_switch.get_active()
type_default = self._type_check_button.get_active()
tid_default = self._tid_check_button.get_active()

View File

@@ -16,7 +16,7 @@ from app.eparser.ecommons import CAS, Flag, BouquetService
from app.eparser.enigma.bouquets import BqServiceType
from app.eparser.iptv import export_to_m3u
from app.eparser.neutrino.bouquets import BqType
from app.settings import Profile, Settings
from app.settings import SettingsType, Settings, SettingsException
from app.tools.media import Player
from app.ui.epg_dialog import EpgDialog
from app.ui.transmitter import LinksTransmitter
@@ -158,8 +158,8 @@ class Application(Gtk.Application):
"on_create_bouquet_for_each_type": self.on_create_bouquet_for_each_type}
self._settings = Settings.get_instance()
self._profile = self._settings.profile
os.makedirs(os.path.dirname(self._settings.data_dir_path), exist_ok=True)
self._s_type = self._settings.setting_type
os.makedirs(os.path.dirname(self._settings.data_local_path), exist_ok=True)
# Used for copy/paste. When adding the previous data will not be deleted.
# Clearing only after the insertion!
self._rows_buffer = []
@@ -188,7 +188,6 @@ class Application(Gtk.Application):
self._EXTRA_COLOR = None # Color for services with a extra name for the bouquet
builder = Gtk.Builder()
builder.set_translation_domain("demon-editor")
builder.add_from_file(UI_RESOURCES_PATH + "main_window.glade")
builder.connect_signals(handlers)
self._main_window = builder.get_object("main_window")
@@ -215,8 +214,8 @@ class Application(Gtk.Application):
self._app_info_box.bind_property("visible", builder.get_object("right_header_box"), "sensitive", 4)
self._app_info_box.bind_property("visible", builder.get_object("left_header_box"), "sensitive", 4)
# Status bar
self._ip_label = builder.get_object("ip_label")
self._ip_label.set_text(self._settings.host)
self._profile_combo_box = builder.get_object("profile_combo_box")
self._profile_combo_box.set_tooltip_text(self._profile_combo_box.get_tooltip_text() + self._settings.host)
self._receiver_info_box = builder.get_object("receiver_info_box")
self._receiver_info_label = builder.get_object("receiver_info_label")
self._signal_box = builder.get_object("signal_box")
@@ -343,7 +342,7 @@ class Application(Gtk.Application):
If update=False - first call on program start, else - after options changes!
"""
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
if self._settings.use_colors:
new_rgb = Gdk.RGBA()
extra_rgb = Gdk.RGBA()
@@ -574,7 +573,7 @@ class Application(Gtk.Application):
# ***************** ####### *********************#
def get_bouquet_file_name(self, bouquet):
bouquet_file_name = "{}userbouquet.{}.{}".format(self._settings.get(self._profile).get("data_dir_path"),
bouquet_file_name = "{}userbouquet.{}.{}".format(self._settings.get(self._s_type).get("data_dir_path"),
*bouquet.split(":"))
return bouquet_file_name
@@ -824,11 +823,11 @@ class Application(Gtk.Application):
@run_task
def on_upload_data(self, download_type):
try:
profile = self._profile
profile = self._s_type
opts = self._settings
use_http = profile is Profile.ENIGMA_2
use_http = profile is SettingsType.ENIGMA_2
if profile is Profile.ENIGMA_2:
if profile is SettingsType.ENIGMA_2:
host, port, user, password = opts.host, opts.http_port, opts.http_user, opts.http_password
try:
test_http(host, port, user, password, skip_message=True)
@@ -858,17 +857,17 @@ class Application(Gtk.Application):
self._wait_dialog.show()
yield True
data_path = self._settings.data_dir_path if data_path is None else data_path
data_path = self._settings.data_local_path if data_path is None else data_path
yield from self.clear_current_data()
try:
prf = self._profile
prf = self._s_type
black_list = get_blacklist(data_path)
bouquets = get_bouquets(data_path, prf)
yield True
services = get_services(data_path, prf, self.get_format_version() if prf is Profile.ENIGMA_2 else 0)
services = get_services(data_path, prf, self.get_format_version() if prf is SettingsType.ENIGMA_2 else 0)
yield True
update_picons_data(self._settings.picons_dir_path, self._picons)
update_picons_data(self._settings.picons_local_path, self._picons)
yield True
except FileNotFoundError as e:
msg = get_message("Please, download files from receiver or setup your path for read data!")
@@ -1009,9 +1008,9 @@ class Application(Gtk.Application):
def save_data(self):
self._save_header_button.set_sensitive(False)
profile = self._profile
path = self._settings.data_dir_path
backup_path = self._settings.backup_dir_path
profile = self._s_type
path = self._settings.data_local_path
backup_path = self._settings.backup_local_path
# Backup data or clearing data path
backup_data(path, backup_path) if self._settings.backup_before_save else clear_data_path(path)
yield True
@@ -1031,7 +1030,7 @@ class Application(Gtk.Application):
favs = self._bouquets[bq_id]
ex_s = self._extra_bouquets.get(bq_id)
bq_s = list(filter(None, [self._services.get(f_id, None) for f_id in favs]))
if profile is Profile.ENIGMA_2:
if profile is SettingsType.ENIGMA_2:
bq_s = list(map(lambda s: s._replace(service=ex_s.get(s.fav_id, None) if ex_s else None), bq_s))
bq = Bouquet(bq_name, bq_type, bq_s, locked, hidden)
bqs.append(bq)
@@ -1045,10 +1044,10 @@ class Application(Gtk.Application):
# Getting services
services_model = get_base_model(self._services_view.get_model())
services = [Service(*row[: Column.SRV_TOOLTIP]) for row in services_model]
write_services(path, services, profile, self.get_format_version() if profile is Profile.ENIGMA_2 else 0)
write_services(path, services, profile, self.get_format_version() if profile is SettingsType.ENIGMA_2 else 0)
yield True
# removing bouquet files
if profile is Profile.ENIGMA_2:
if profile is SettingsType.ENIGMA_2:
# blacklist
write_blacklist(path, self._blacklist)
@@ -1060,7 +1059,7 @@ class Application(Gtk.Application):
if show_dialog(DialogType.QUESTION, self._main_window) == Gtk.ResponseType.CANCEL:
return
gen = self.create_new_configuration(self._profile)
gen = self.create_new_configuration(self._s_type)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def create_new_configuration(self, profile):
@@ -1070,12 +1069,12 @@ class Application(Gtk.Application):
c_gen = self.clear_current_data()
yield from c_gen
if profile is Profile.ENIGMA_2:
if profile is SettingsType.ENIGMA_2:
parent = self._bouquets_model.append(None, ["Favourites (TV)", None, None, BqType.TV.value])
self.append_bouquet(Bouquet("Favourites (TV)", BqType.TV.value, [], None, None), parent)
parent = self._bouquets_model.append(None, ["Favourites (Radio)", None, None, BqType.RADIO.value])
self.append_bouquet(Bouquet("Favourites (Radio)", BqType.RADIO.value, [], None, None), parent)
elif profile is Profile.NEUTRINO_MP:
elif profile is SettingsType.NEUTRINO_MP:
self._bouquets_model.append(None, ["Providers", None, None, BqType.BOUQUET.value])
self._bouquets_model.append(None, ["FAV", None, None, BqType.TV.value])
self._bouquets_model.append(None, ["WEBTV", None, None, BqType.WEBTV.value])
@@ -1143,7 +1142,7 @@ class Application(Gtk.Application):
self.show_error_dialog("Error. No bouquet is selected!")
return
if self._profile is Profile.NEUTRINO_MP and self._bq_selected.endswith(BqType.WEBTV.value):
if self._s_type is SettingsType.NEUTRINO_MP and self._bq_selected.endswith(BqType.WEBTV.value):
self.show_error_dialog("Operation not allowed in this context!")
return
@@ -1175,11 +1174,11 @@ class Application(Gtk.Application):
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def update_options(self):
profile = self._settings.profile
self._ip_label.set_text(self._settings.host)
if profile != self._profile:
profile = self._settings.setting_type
if profile != self._s_type:
yield from self.show_app_info(True)
self._profile = profile
self._s_type = profile
c_gen = self.clear_current_data()
yield from c_gen
self.update_profile_label()
@@ -1284,7 +1283,7 @@ class Application(Gtk.Application):
self._tool_elements[elem].set_sensitive(not_empty)
if elem == "bouquets_paste_popup_item":
self._tool_elements[elem].set_sensitive(not_empty and self._bouquets_buffer)
if self._profile is Profile.NEUTRINO_MP:
if self._s_type is SettingsType.NEUTRINO_MP:
for elem in self._LOCK_HIDE_ELEMENTS:
self._tool_elements[elem].set_sensitive(not_empty)
else:
@@ -1300,17 +1299,17 @@ class Application(Gtk.Application):
for elem in self._BOUQUET_ELEMENTS:
self._tool_elements[elem].set_sensitive(False)
for elem in self._LOCK_HIDE_ELEMENTS:
self._tool_elements[elem].set_sensitive(not_empty and self._profile is Profile.ENIGMA_2)
self._tool_elements[elem].set_sensitive(not_empty and self._s_type is SettingsType.ENIGMA_2)
for elem in self._FAV_IPTV_ELEMENTS:
is_iptv = self._bq_selected and not is_service
if self._profile is Profile.NEUTRINO_MP:
if self._s_type is SettingsType.NEUTRINO_MP:
is_iptv = is_iptv and BqType(self._bq_selected.split(":")[1]) is BqType.WEBTV
self._tool_elements[elem].set_sensitive(is_iptv)
for elem in self._COMMONS_ELEMENTS:
self._tool_elements[elem].set_sensitive(not_empty)
if self._profile is not Profile.ENIGMA_2:
if self._s_type is not SettingsType.ENIGMA_2:
for elem in self._FAV_ENIGMA_ELEMENTS:
self._tool_elements[elem].set_sensitive(False)
@@ -1321,9 +1320,9 @@ class Application(Gtk.Application):
self.set_service_flags(Flag.LOCK)
def set_service_flags(self, flag):
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
set_flags(flag, self._services_view, self._fav_view, self._services, self._blacklist)
elif self._profile is Profile.NEUTRINO_MP and self._bq_selected:
elif self._s_type is SettingsType.NEUTRINO_MP and self._bq_selected:
model, paths = self._bouquets_view.get_selection().get_selected_rows()
itr = model.get_iter(paths[0])
value = model.get_value(itr, 1 if flag is Flag.LOCK else 2)
@@ -1386,14 +1385,14 @@ class Application(Gtk.Application):
self._fav_view,
self._services,
self._bouquets.get(self._bq_selected, None),
self._profile,
self._s_type,
Action.ADD).show()
if response != Gtk.ResponseType.CANCEL:
self.update_fav_num_column(self._fav_model)
@run_idle
def on_iptv_list_configuration(self, item):
if self._profile is Profile.NEUTRINO_MP:
if self._s_type is SettingsType.NEUTRINO_MP:
self.show_error_dialog("Neutrino at the moment not supported!")
return
@@ -1407,7 +1406,7 @@ class Application(Gtk.Application):
bq = self._bouquets.get(self._bq_selected, [])
IptvListConfigurationDialog(self._main_window, self._services, iptv_rows, bq,
self._fav_model, self._profile).show()
self._fav_model, self._s_type).show()
@run_idle
def on_remove_all_unavailable(self, item):
@@ -1423,7 +1422,7 @@ class Application(Gtk.Application):
return
fav_bqt = self._bouquets.get(self._bq_selected, None)
response = SearchUnavailableDialog(self._main_window, self._fav_model, fav_bqt, iptv_rows, self._profile).show()
response = SearchUnavailableDialog(self._main_window, self._fav_model, fav_bqt, iptv_rows, self._s_type).show()
if response:
next(self.remove_favs(response, self._fav_model), False)
@@ -1431,7 +1430,7 @@ class Application(Gtk.Application):
@run_idle
def on_epg_list_configuration(self, item):
if self._profile is not Profile.ENIGMA_2:
if self._s_type is not SettingsType.ENIGMA_2:
self.show_error_dialog("Only Enigma2 is supported!")
return
@@ -1449,7 +1448,7 @@ class Application(Gtk.Application):
if not self._bq_selected:
return
YtListImportDialog(self._main_window, self._profile, self.append_imported_services).show()
YtListImportDialog(self._main_window, self._s_type, self.append_imported_services).show()
def on_import_m3u(self, item):
""" Imports iptv from m3u files. """
@@ -1461,7 +1460,7 @@ class Application(Gtk.Application):
self.show_error_dialog("No m3u file is selected!")
return
channels = parse_m3u(response, self._profile)
channels = parse_m3u(response, self._s_type)
if channels and self._bq_selected:
self.append_imported_services(channels)
@@ -1492,7 +1491,7 @@ class Application(Gtk.Application):
try:
bq = Bouquet(self._current_bq_name, None, bq_services, None, None)
export_to_m3u(response, bq, self._profile)
export_to_m3u(response, bq, self._s_type)
except Exception as e:
self.show_error_dialog(str(e))
else:
@@ -1504,7 +1503,7 @@ class Application(Gtk.Application):
self.show_error_dialog("No selected item!")
return
appender = self.append_bouquet if self._profile is Profile.ENIGMA_2 else self.append_bouquets
appender = self.append_bouquet if self._s_type is SettingsType.ENIGMA_2 else self.append_bouquets
import_bouquet(self._main_window, model, paths[0], self._settings, self._services, appender)
def on_import_bouquets(self, item):
@@ -1545,7 +1544,7 @@ class Application(Gtk.Application):
self.show_error_dialog("Not allowed in this context!")
return
url = get_iptv_url(row, self._profile)
url = get_iptv_url(row, self._s_type)
self.update_player_buttons()
if not url:
return
@@ -1659,10 +1658,11 @@ class Application(Gtk.Application):
def init_http_api(self):
self._fav_click_mode = FavClickMode(self._settings.fav_click_mode)
http_api_enable = self._settings.http_api_support
status = all((http_api_enable, self._profile is Profile.ENIGMA_2, not self._receiver_info_box.get_visible()))
status = all(
(http_api_enable, self._s_type is SettingsType.ENIGMA_2, not self._receiver_info_box.get_visible()))
GLib.idle_add(self._http_status_image.set_visible, status)
if self._profile is Profile.NEUTRINO_MP or not http_api_enable:
if self._s_type is SettingsType.NEUTRINO_MP or not http_api_enable:
self.update_info_boxes_visible(False)
if self._http_api:
self._http_api.close()
@@ -1786,7 +1786,7 @@ class Application(Gtk.Application):
self._sat_positions.clear()
sat_positions = set()
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
terrestrial = False
cable = False
@@ -1803,7 +1803,7 @@ class Application(Gtk.Application):
self._sat_positions.append("T")
if cable:
self._sat_positions.append("C")
elif self._profile is Profile.NEUTRINO_MP:
elif self._s_type is SettingsType.NEUTRINO_MP:
list(map(lambda s: sat_positions.add(float(s.pos)), filter(lambda s: s.pos, self._services.values())))
self._sat_positions.extend(map(str, sorted(sat_positions)))
@@ -1881,7 +1881,7 @@ class Application(Gtk.Application):
self._fav_view,
self._services,
self._bouquets.get(self._bq_selected, None),
self._profile,
self._s_type,
Action.EDIT).show()
self.on_locate_in_services(view)
@@ -1999,7 +1999,7 @@ class Application(Gtk.Application):
@run_idle
def on_picons_loader_show(self, item):
ids = {}
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
for r in self._services_model:
data = r[Column.SRV_PICON_ID].split("_")
ids["{}:{}:{}".format(data[3], data[5], data[6])] = r[Column.SRV_PICON_ID]
@@ -2009,7 +2009,7 @@ class Application(Gtk.Application):
@run_task
def update_picons(self):
update_picons_data(self._settings.picons_dir_path, self._picons)
update_picons_data(self._settings.picons_local_path, self._picons)
append_picons(self._picons, self._services_model)
def on_assign_picon(self, view):
@@ -2062,15 +2062,20 @@ class Application(Gtk.Application):
def create_bouquets(self, g_type):
gen_bouquets(self._services_view, self._bouquets_view, self._main_window, g_type, self._TV_TYPES,
self._profile, self.append_bouquet)
self._s_type, self.append_bouquet)
# ***************** Profile label *********************#
def update_profile_label(self):
if self._profile is Profile.ENIGMA_2:
self._header_bar.set_subtitle("{} Enigma2 v.{}".format(get_message("Profile:"), self.get_format_version()))
elif self._profile is Profile.NEUTRINO_MP:
self._header_bar.set_subtitle("{} Neutrino-MP".format(get_message("Profile:")))
label, sep, ip = self._profile_combo_box.get_tooltip_text().partition(":")
profile_name = self._profile_combo_box.get_active_text()
self._profile_combo_box.set_tooltip_text("{}: {}".format(label, self._settings.host))
msg = get_message("Profile:")
if self._s_type is SettingsType.ENIGMA_2:
self._header_bar.set_subtitle("{} {} [Enigma2 v.{}]".format(msg, profile_name, self.get_format_version()))
elif self._s_type is SettingsType.NEUTRINO_MP:
self._header_bar.set_subtitle("{} {} [Neutrino-MP]".format(msg, profile_name))
def get_format_version(self):
return 5 if self._settings.v5_support else 4
@@ -2086,8 +2091,14 @@ class Application(Gtk.Application):
def start_app():
app = Application()
app.run(sys.argv)
try:
Settings.get_instance()
except SettingsException as e:
msg = "{} \n{}".format(e, "All setting were reset. Restart the program!")
show_dialog(DialogType.INFO, transient=Gtk.Dialog(), text=msg)
else:
app = Application()
app.run(sys.argv)
if __name__ == "__main__":

View File

@@ -9,7 +9,7 @@ from app.commons import run_task
from app.eparser import Service
from app.eparser.ecommons import Flag, BouquetService, Bouquet, BqType
from app.eparser.enigma.bouquets import BqServiceType, to_bouquet_id
from app.settings import Profile
from app.settings import SettingsType
from .uicommons import ViewTarget, BqGenType, Gtk, Gdk, HIDE_ICON, LOCKED_ICON, KeyboardKey, Column
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog
@@ -382,7 +382,7 @@ def assign_picon(target, srv_view, fav_view, transient, picons, settings, servic
if picon_id:
if os.path.isfile(response):
picons_path = settings.picons_dir_path
picons_path = settings.picons_local_path
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
picon_file = picons_path + picon_id
shutil.copy(response, picon_file)
@@ -464,8 +464,8 @@ def remove_all_unused_picons(settings, picons, services):
def remove_picons(settings, picon_ids, picons):
pions_path = settings.picons_dir_path
backup_path = settings.backup_dir_path + "picons/"
pions_path = settings.picons_local_path
backup_path = settings.backup_local_path + "picons/"
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
for p_id in picon_ids:
picons[p_id] = None
@@ -492,7 +492,7 @@ def get_picon_pixbuf(path):
# ***************** Bouquets *********************#
def gen_bouquets(view, bq_view, transient, gen_type, tv_types, profile, callback):
def gen_bouquets(view, bq_view, transient, gen_type, tv_types, s_type, callback):
""" Auto-generate and append list of bouquets """
fav_id_index = Column.SRV_FAV_ID
index = Column.SRV_TYPE
@@ -502,7 +502,7 @@ def gen_bouquets(view, bq_view, transient, gen_type, tv_types, profile, callback
index = Column.SRV_POS
model, paths = view.get_selection().get_selected_rows()
bq_type = BqType.BOUQUET.value if profile is Profile.NEUTRINO_MP else BqType.TV.value
bq_type = BqType.BOUQUET.value if s_type is SettingsType.NEUTRINO_MP else BqType.TV.value
if gen_type in (BqGenType.SAT, BqGenType.PACKAGE, BqGenType.TYPE):
if not is_only_one_item_selected(paths, transient):
return
@@ -511,17 +511,17 @@ def gen_bouquets(view, bq_view, transient, gen_type, tv_types, profile, callback
bq_type = BqType.RADIO.value
append_bouquets(bq_type, bq_view, callback, fav_id_index, index, model,
[service.package if gen_type is BqGenType.PACKAGE else
service.pos if gen_type is BqGenType.SAT else service.service_type], profile)
service.pos if gen_type is BqGenType.SAT else service.service_type], s_type)
else:
wait_dialog = WaitDialog(transient)
wait_dialog.show()
append_bouquets(bq_type, bq_view, callback, fav_id_index, index, model,
{row[index] for row in model}, profile, wait_dialog)
{row[index] for row in model}, s_type, wait_dialog)
@run_task
def append_bouquets(bq_type, bq_view, callback, fav_id_index, index, model, names, profile, wait_dialog=None):
bq_index = 0 if profile is Profile.ENIGMA_2 else 1
def append_bouquets(bq_type, bq_view, callback, fav_id_index, index, model, names, s_type, wait_dialog=None):
bq_index = 0 if s_type is SettingsType.ENIGMA_2 else 1
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
bqs_model = bq_view.get_model()
bouquets_names = get_bouquets_names(bqs_model)
@@ -583,14 +583,14 @@ def append_text_to_tview(char, view):
view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
def get_iptv_url(row, profile):
def get_iptv_url(row, s_type):
""" Returns url from iptv type row """
data = row[Column.FAV_ID].split(":" if profile is Profile.ENIGMA_2 else "::")
if profile is Profile.ENIGMA_2:
data = row[Column.FAV_ID].split(":" if s_type is SettingsType.ENIGMA_2 else "::")
if s_type is SettingsType.ENIGMA_2:
data = list(filter(lambda x: "http" in x, data))
if data:
url = data[0]
return urllib.request.unquote(url) if profile is Profile.ENIGMA_2 else url
return urllib.request.unquote(url) if s_type is SettingsType.ENIGMA_2 else url
def on_popup_menu(menu, event):

View File

@@ -26,7 +26,7 @@ THE SOFTWARE.
Author: Dmitriy Yefremov
-->
<interface>
<interface domain="demon-editor">
<requires lib="gtk+" version="3.16"/>
<!-- interface-css-provider-path style.css -->
<!-- interface-license-type mit -->
@@ -961,6 +961,7 @@ Author: Dmitriy Yefremov
</object>
<object class="GtkApplicationWindow" id="main_window">
<property name="width_request">640</property>
<property name="height_request">480</property>
<property name="can_focus">False</property>
<property name="window_position">center</property>
<property name="icon_name">accessories-text-editor</property>
@@ -2798,7 +2799,7 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkBox" id="status_bar_box">
<property name="height_request">30</property>
<property name="height_request">35</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="receiver_info_box">
@@ -2842,62 +2843,56 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child type="center">
<object class="GtkBox" id="ip_status_box">
<property name="visible">True</property>
<object class="GtkComboBoxText" id="profile_combo_box">
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="tooltip_text" translatable="yes">Current IP:</property>
<property name="halign">center</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage" id="ip_status_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-connect</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ip_status_label">
<property name="visible">True</property>
<property name="valign">center</property>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<property name="active">0</property>
<property name="has_frame">False</property>
<property name="has_entry">True</property>
<items>
<item translatable="yes">default</item>
</items>
<child internal-child="entry">
<object class="GtkEntry">
<property name="can_focus">False</property>
<property name="has_tooltip">True</property>
<property name="halign">center</property>
<property name="label" translatable="yes">Current IP:</property>
<attributes>
<attribute name="size" value="8000"/>
</attributes>
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<property name="editable">False</property>
<property name="has_frame">False</property>
<property name="max_width_chars">9</property>
<property name="text" translatable="yes">default</property>
<property name="primary_icon_stock">gtk-connect</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ip_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">127.0.0.1</property>
<attributes>
<attribute name="size" value="8000"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkImage" id="http_status_image">
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">No connection to the receiver</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="icon_name">network-offline</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="signal_box">
<property name="can_focus">False</property>
@@ -2986,21 +2981,6 @@ Author: Dmitriy Yefremov
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkImage" id="http_status_image">
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">No connection to the receiver</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="icon_name">network-offline</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
<style>
<class name="primary-toolbar"/>
</style>

View File

@@ -9,7 +9,7 @@ from gi.repository import GLib, GdkPixbuf
from app.commons import run_idle, run_task
from app.connections import upload_data, DownloadType
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
from app.settings import Profile
from app.settings import SettingsType
from app.tools.satellites import SatellitesParser, SatelliteSource
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON
from .dialogs import show_dialog, DialogType, get_message
@@ -86,13 +86,13 @@ class PiconsDialog:
self._url_entry.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
self._settings = settings
self._profile = settings.profile
self._s_type = settings.setting_type
self._ip_entry.set_text(self._settings.host)
self._picons_entry.set_text(self._settings.picons_path)
self._picons_path = self._settings.picons_dir_path
self._picons_path = self._settings.picons_local_path
self._picons_dir_entry.set_text(self._picons_path)
if not len(self._picon_ids) and self._profile is Profile.ENIGMA_2:
if not len(self._picon_ids) and self._s_type is SettingsType.ENIGMA_2:
message = get_message("To automatically set the identifiers for picons,\n"
"first load the required services list into the main application window.")
self.show_info_message(message, Gtk.MessageType.WARNING)
@@ -342,7 +342,7 @@ class PiconsDialog:
self._expander.set_expanded(True)
convert_to(src_path=picons_path,
dest_path=save_path,
profile=Profile.ENIGMA_2,
s_type=SettingsType.ENIGMA_2,
callback=self.append_output,
done_callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO))
@@ -362,10 +362,10 @@ class PiconsDialog:
show_dialog(dialog_type, self._dialog, message)
def get_picons_format(self):
picon_format = Profile.ENIGMA_2
picon_format = SettingsType.ENIGMA_2
if self._neutrino_mp_radio_button.get_active():
picon_format = Profile.NEUTRINO_MP
picon_format = SettingsType.NEUTRINO_MP
return picon_format

View File

@@ -25,7 +25,7 @@ class SatellitesDialog:
_aggr = [None for x in range(9)] # aggregate
def __init__(self, transient, settings):
self._data_path = settings.data_dir_path + "satellites.xml"
self._data_path = settings.data_local_path + "satellites.xml"
self._settings = settings
handlers = {"on_open": self.on_open,

View File

@@ -6,7 +6,7 @@ from app.eparser import Service
from app.eparser.ecommons import MODULATION, Inversion, ROLL_OFF, Pilot, Flag, Pids, POLARIZATION, \
get_key_by_value, get_value_by_name, FEC_DEFAULT, PLS_MODE, SERVICE_TYPE, T_MODULATION, C_MODULATION, TrType, \
SystemCable, T_SYSTEM, BANDWIDTH, TRANSMISSION_MODE, GUARD_INTERVAL, HIERARCHY, T_FEC
from app.settings import Profile
from app.settings import SettingsType
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HIDE_ICON, TEXT_DOMAIN, CODED_ICON, Column, IS_GNOME_SESSION
from .dialogs import show_dialog, DialogType, Action, get_dialogs_string
from .main_helper import get_base_model
@@ -52,10 +52,10 @@ class ServiceDetailsDialog:
self._dialog = builder.get_object("service_details_dialog")
self._dialog.set_transient_for(transient)
self._profile = settings.profile
self._s_type = settings.setting_type
self._tr_type = None
self._satellites_xml_path = settings.data_dir_path + "satellites.xml"
self._picons_dir_path = settings.picons_dir_path
self._satellites_xml_path = settings.data_local_path + "satellites.xml"
self._picons_dir_path = settings.picons_local_path
self._services_view = srv_view
self._fav_view = fav_view
self._action = action
@@ -197,7 +197,7 @@ class ServiceDetailsDialog:
self._package_entry.set_text(srv.package)
self._sid_entry.set_text(str(int(srv.ssid, 16)))
# Transponder
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
self._tr_type = TrType(srv.transponder_type)
self._freq_entry.set_text(srv.freq)
self._rate_entry.set_text(srv.rate)
@@ -211,10 +211,10 @@ class ServiceDetailsDialog:
else:
self.set_sat_positions(srv.pos)
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
self.init_enigma2_service_data(srv)
self.init_enigma2_transponder_data(srv)
elif self._profile is Profile.NEUTRINO_MP:
elif self._s_type is SettingsType.NEUTRINO_MP:
self.init_neutrino_data(srv)
self.init_neutrino_ui_elements()
@@ -484,9 +484,9 @@ class ServiceDetailsDialog:
transponder=transponder)
def get_flags(self):
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
return self.get_enigma2_flags()
elif self._profile is Profile.NEUTRINO_MP:
elif self._s_type is SettingsType.NEUTRINO_MP:
return self._old_service.flags_cas
def get_enigma2_flags(self):
@@ -532,12 +532,12 @@ class ServiceDetailsDialog:
net_id, tr_id = int(self._network_id_entry.get_text()), int(self._transponder_id_entry.get_text())
service_type = self._srv_type_entry.get_text()
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
namespace = int(self._namespace_entry.get_text())
data_id = self._ENIGMA2_DATA_ID.format(ssid, namespace, tr_id, net_id, service_type, 0)
fav_id = self._ENIGMA2_FAV_ID.format(ssid, tr_id, net_id, namespace)
return fav_id, data_id
elif self._profile is Profile.NEUTRINO_MP:
elif self._s_type is SettingsType.NEUTRINO_MP:
fav_id = self._NEUTRINO_FAV_ID.format(tr_id, net_id, ssid)
return fav_id, self._old_service.data_id
@@ -548,7 +548,7 @@ class ServiceDetailsDialog:
fec = self._fec_combo_box.get_active_id()
system = self._sys_combo_box.get_active_id()
if self._tr_type is TrType.Satellite or self._profile is Profile.NEUTRINO_MP:
if self._tr_type is TrType.Satellite or self._s_type is SettingsType.NEUTRINO_MP:
freq = self._freq_entry.get_text()
rate = self._rate_entry.get_text()
pol = self._pol_combo_box.get_active_id()
@@ -571,7 +571,7 @@ class ServiceDetailsDialog:
inv = get_value_by_name(Inversion, self._invertion_combo_box.get_active_id())
srv_sys = "0" # !!!
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
dvb_s_tr = self._ENIGMA2_TRANSPONDER_DATA.format("s", freq, rate, pol, fec, sat_pos, inv, srv_sys)
if sys == "DVB-S":
return dvb_s_tr
@@ -585,7 +585,7 @@ class ServiceDetailsDialog:
st_id = self._stream_id_entry.get_text()
pls = ":{}:{}:{}".format(st_id, pls_code, pls_mode) if pls_mode and pls_code and st_id else ""
return "{}:{}:{}:{}:{}{}".format(dvb_s_tr, flag, mod, roll_off, pilot, pls)
elif self._profile is Profile.NEUTRINO_MP:
elif self._s_type is SettingsType.NEUTRINO_MP:
on_id, tr_id = int(self._network_id_entry.get_text()), int(self._transponder_id_entry.get_text())
mod = self.get_value_from_combobox_id(self._mod_combo_box, MODULATION) if sys == "DVB-S2" else None
srv_sys = None
@@ -682,7 +682,7 @@ class ServiceDetailsDialog:
return True
def update_reference(self, entry, event=None):
if not self.is_data_correct() or (event is None and self._profile is Profile.NEUTRINO_MP):
if not self.is_data_correct() or (event is None and self._s_type is SettingsType.NEUTRINO_MP):
return
self.update_reference_entry()
@@ -691,7 +691,7 @@ class ServiceDetailsDialog:
ssid = int(self._sid_entry.get_text())
tid = int(self._transponder_id_entry.get_text())
nid = int(self._network_id_entry.get_text())
if self._profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
on_id = int(self._namespace_entry.get_text())
ref = "1:0:{:X}:{:X}:{:X}:{:X}:{:X}:0:0:0".format(srv_type, ssid, tid, nid, on_id)
self._reference_entry.set_text(ref)

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@ from enum import Enum
from app.commons import run_task, run_idle
from app.connections import test_telnet, test_ftp, TestException, test_http
from app.settings import Profile
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, FavClickMode
from app.settings import SettingsType
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON
from .main_helper import update_entry_data
@@ -21,7 +21,7 @@ class SettingsDialog:
def __init__(self, transient, settings):
handlers = {"on_field_icon_press": self.on_field_icon_press,
"on_profile_changed": self.on_profile_changed,
"on_settings_type_changed": self.on_settings_type_changed,
"on_reset": self.on_reset,
"apply_settings": self.apply_settings,
"on_connection_test": self.on_connection_test,
@@ -29,10 +29,16 @@ class SettingsDialog:
"on_set_color_switch_state": self.on_set_color_switch_state,
"on_http_mode_switch_state": self.on_http_mode_switch_state,
"on_yt_dl_switch_state": self.on_yt_dl_switch_state,
"on_send_to_switch_state": self.on_send_to_switch_state}
"on_send_to_switch_state": self.on_send_to_switch_state,
"on_profile_add": self.on_profile_add,
"on_profile_edit": self.on_profile_edit,
"on_profile_remove": self.on_profile_remove,
"on_profile_deleted": self.on_profile_deleted,
"on_profile_inserted": self.on_profile_inserted,
"on_profile_edited": self.on_profile_edited,
"on_profile_set_default": self.on_profile_set_default}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_file(UI_RESOURCES_PATH + "settings_dialog.glade")
builder.connect_signals(handlers)
@@ -89,23 +95,38 @@ class SettingsDialog:
self._click_mode_zap_button.bind_property("sensitive", self._enable_send_to_switch, "sensitive")
self._enable_send_to_switch.bind_property("sensitive", builder.get_object("enable_send_to_label"), "sensitive")
self._extra_support_grid.bind_property("sensitive", builder.get_object("v5_support_grid"), "sensitive")
# Profiles
self._profile_view = builder.get_object("profile_tree_view")
self._profile_remove_button = builder.get_object("profile_remove_button")
self._profile_view.get_model().append(("default", DEFAULT_ICON))
# Settings
self._settings = settings
self._active_profile = settings.profile
self._profiles = settings.profiles
self._s_type = settings.setting_type
self.set_settings()
self.init_ui_elements(self._active_profile)
self.init_ui_elements(self._s_type)
def init_ui_elements(self, profile):
is_enigma_profile = profile is Profile.ENIGMA_2
self._neutrino_radio_button.set_active(profile is Profile.NEUTRINO_MP)
@run_idle
def init_ui_elements(self, s_type):
is_enigma_profile = s_type is SettingsType.ENIGMA_2
self._neutrino_radio_button.set_active(s_type is SettingsType.NEUTRINO_MP)
self.update_header_bar()
self._settings_stack.get_child_by_name(Property.HTTP.value).set_visible(is_enigma_profile)
self._program_frame.set_sensitive(is_enigma_profile)
self._extra_support_grid.set_sensitive(is_enigma_profile)
http_active = self._support_http_api_switch.get_active()
self._click_mode_zap_button.set_sensitive(is_enigma_profile and http_active)
self._profile_remove_button.set_sensitive(len(self._profile_view.get_model()) > 1)
self.on_info_bar_close() if is_enigma_profile else self.show_info_message(
"The Neutrino has only experimental support. Not all features are supported!", Gtk.MessageType.WARNING)
def update_header_bar(self):
label, sep, st = self._header_bar.get_subtitle().partition(":")
if self._s_type is SettingsType.ENIGMA_2:
self._header_bar.set_subtitle("{}: {}".format(label, self._enigma_radio_button.get_label()))
elif self._s_type is SettingsType.NEUTRINO_MP:
self._header_bar.set_subtitle("{}: {}".format(label, self._neutrino_radio_button.get_label()))
def show(self):
response = self._dialog.run()
if response == Gtk.ResponseType.OK:
@@ -117,10 +138,10 @@ class SettingsDialog:
def on_field_icon_press(self, entry, icon, event_button):
update_entry_data(entry, self._dialog, self._settings)
def on_profile_changed(self, item):
profile = Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP
self._active_profile = profile
self._settings.profile = profile
def on_settings_type_changed(self, item):
profile = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
self._s_type = profile
self._settings.setting_type = profile
self.set_settings()
self.init_ui_elements(profile)
@@ -144,14 +165,14 @@ class SettingsDialog:
self._user_bouquet_field.set_text(self._settings.user_bouquet_path)
self._satellites_xml_field.set_text(self._settings.satellites_xml_path)
self._picons_field.set_text(self._settings.picons_path)
self._data_dir_field.set_text(self._settings.data_dir_path)
self._picons_dir_field.set_text(self._settings.picons_dir_path)
self._backup_dir_field.set_text(self._settings.backup_dir_path)
self._data_dir_field.set_text(self._settings.data_local_path)
self._picons_dir_field.set_text(self._settings.picons_local_path)
self._backup_dir_field.set_text(self._settings.backup_local_path)
self._before_save_switch.set_active(self._settings.backup_before_save)
self._before_downloading_switch.set_active(self._settings.backup_before_downloading)
self.set_fav_click_mode(self._settings.fav_click_mode)
if self._active_profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
self._support_ver5_switch.set_active(self._settings.v5_support)
self._support_http_api_switch.set_active(self._settings.http_api_support)
self._enable_y_dl_switch.set_active(self._settings.enable_yt_dl)
@@ -165,8 +186,8 @@ class SettingsDialog:
self._extra_color_button.set_rgba(extra_rgb)
def apply_settings(self, item=None):
self._active_profile = Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP
self._settings.profile = self._active_profile
self._s_type = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
self._settings.setting_type = self._s_type
self._settings.host = self._host_field.get_text()
self._settings.port = self._port_field.get_text()
self._settings.user = self._login_field.get_text()
@@ -182,14 +203,14 @@ class SettingsDialog:
self._settings.user_bouquet_path = self._user_bouquet_field.get_text()
self._settings.satellites_xml_path = self._satellites_xml_field.get_text()
self._settings.picons_path = self._picons_field.get_text()
self._settings.data_dir_path = self._data_dir_field.get_text()
self._settings.picons_dir_path = self._picons_dir_field.get_text()
self._settings.backup_dir_path = self._backup_dir_field.get_text()
self._settings.data_local_path = self._data_dir_field.get_text()
self._settings.picons_local_path = self._picons_dir_field.get_text()
self._settings.backup_local_path = self._backup_dir_field.get_text()
self._settings.backup_before_save = self._before_save_switch.get_active()
self._settings.backup_before_downloading = self._before_downloading_switch.get_active()
self._settings.fav_click_mode = self.get_fav_click_mode()
if self._active_profile is Profile.ENIGMA_2:
if self._s_type is SettingsType.ENIGMA_2:
self._settings.use_colors = self._set_color_switch.get_active()
self._settings.new_color = self._new_color_button.get_rgba().to_string()
self._settings.extra_color = self._extra_color_button.get_rgba().to_string()
@@ -272,6 +293,42 @@ class SettingsDialog:
def on_send_to_switch_state(self, switch, state):
self.show_info_message("Not implemented yet!", Gtk.MessageType.WARNING)
def on_profile_add(self, item):
model = self._profile_view.get_model()
count = 0
name = "profile"
while name in self._profiles:
count += 1
name = "profile{}".format(count)
self._profiles[name] = {"host": self._host_field.get_text()}
itr = model.append((name, None))
def on_profile_edit(self, item):
self.show_info_message("Not implemented yet!", Gtk.MessageType.WARNING)
def on_profile_remove(self, item):
model, paths = self._profile_view.get_selection().get_selected_rows()
if paths:
row = model[paths]
self._profiles.pop(row[0], None)
del model[paths]
def on_profile_deleted(self, model, paths):
self._profile_remove_button.set_sensitive(len(model) > 1)
def on_profile_edited(self, render, path, new_text):
p_name = render.get_property("text")
p_data = self._profiles.pop(p_name, None)
row = self._profile_view.get_model()[path]
row[0] = new_text
self._profiles[new_text] = p_data
def on_profile_set_default(self, item):
self.show_info_message("Not implemented yet!", Gtk.MessageType.WARNING)
def on_profile_inserted(self, model, path, itr):
self._profile_remove_button.set_sensitive(len(model) > 1)
@run_idle
def set_fav_click_mode(self, mode):
mode = FavClickMode(mode)

View File

@@ -28,6 +28,7 @@ HIDE_ICON = theme.load_icon("go-jump", 16, 0) if theme.lookup_icon("go-jump", 16
TV_ICON = theme.load_icon("tv-symbolic", 16, 0) if theme.lookup_icon("tv-symbolic", 16, 0) else _IMAGE_MISSING
IPTV_ICON = theme.load_icon("emblem-shared", 16, 0) if theme.lookup_icon("emblem-shared", 16, 0) else None
EPG_ICON = theme.load_icon("gtk-index", 16, 0) if theme.lookup_icon("gtk-index", 16, 0) else None
DEFAULT_ICON = theme.load_icon("emblem-default", 16, 0) if theme.lookup_icon("emblem-default", 16, 0) else None
class KeyboardKey(Enum):