diff --git a/.env.dist b/.env.dist index e85a698..1ff36e8 100755 --- a/.env.dist +++ b/.env.dist @@ -1,4 +1,3 @@ DEBUG=false PORT=5000 -AUTOCONFIGURE_REVERSE_PROXY_MODE=false AUTOCONFIGURE_LX_FILE=/home/pi/.config/lxsession/LXDE-pi/autostart # Replace by "./var/run/dummy" if not needed diff --git a/README.md b/README.md index b1cc038..ee7f932 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ mkdir -p obscreen/data/db obscreen/data/uploads && cd obscreen docker run --rm --name obscreen --pull=always \ -e DEBUG=false \ -e PORT=5000 \ - -e AUTOCONFIGURE_REVERSE_PROXY_MODE=false \ -e AUTOCONFIGURE_LX_FILE=/app/var/run/lxfile \ -p 5000:5000 \ -v ./data/db:/app/data/db \ @@ -98,7 +97,6 @@ sudo journalctl -u obscreen -f ``` ## 👌 Usage -- Hostname will be http://localhost:5000 or http://localhost with nginx or http://[SERVER_IP]:[PORT] - Page which plays slideshow is reachable at `http://localhost:5000` - Slideshow manager is reachable at `http://localhost:5000/manage` @@ -108,7 +106,7 @@ sudo journalctl -u obscreen -f ## 📎 Additional -### A. Hardware checks +### Hardware checks - Basic Setup For basic RaspberryPi setup you can use most of the available guides, for example this one: https://gist.github.com/blackjid/dfde6bedef148253f987 @@ -118,13 +116,3 @@ You may need to set the HDMI Mode on the raspi to ensure the hdmi resolution mat https://www.raspberrypi.org/documentation/configuration/config-txt/video.md However, I used this one: `(2,82) = 1920x1080 60Hz 1080p` - -### B. Nginx server to serve pages (useful for gzip compression for instance) -1. Install -```bash -sudo apt install -y nginx -sudo rm /etc/nginx/sites-enabled/default 2>/dev/null -sudo ln -s "$(pwd)/system/nginx-obscreen" /etc/nginx/sites-enabled -sudo systemctl reload nginx -``` -2. Set `autoconfigure_reverse_proxy_mode` to `true` in `.env` file diff --git a/data/www/css/main.css b/data/www/css/main.css index 833f222..fbac64c 100644 --- a/data/www/css/main.css +++ b/data/www/css/main.css @@ -27,6 +27,10 @@ body { align-self: stretch; } +.invisible { + visibility: hidden !important; +} + .hidden { display: none !important; } @@ -280,7 +284,6 @@ button.purple:hover { .panel td.infos { display: flex; flex-direction: row; - width: 400px; justify-content: flex-start; align-items: flex-start; } diff --git a/data/www/js/settings.js b/data/www/js/settings.js index e501d7c..2359534 100644 --- a/data/www/js/settings.js +++ b/data/www/js/settings.js @@ -35,6 +35,7 @@ jQuery(document).ready(function ($) { showModal('modal-variable-edit'); $('.modal-variable-edit input:visible:eq(0)').focus().select(); $('#variable-edit-name').val(variable.name); + $('#variable-edit-description').html(variable.description); $('#variable-edit-value').val(variable.value); $('#variable-edit-id').val(variable.id); }); diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 0e9f667..4c419ad 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -9,7 +9,6 @@ services: environment: - DEBUG=${DEBUG-false} - PORT=${PORT-5000} - - AUTOCONFIGURE_REVERSE_PROXY_MODE=${AUTOCONFIGURE_REVERSE_PROXY_MODE-false} - AUTOCONFIGURE_LX_FILE=/app/var/run/lxfile volumes: - .:/app diff --git a/docker-compose.yml b/docker-compose.yml index 95d94ca..99706a1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,6 @@ services: environment: - DEBUG=false - PORT=5000 - - AUTOCONFIGURE_REVERSE_PROXY_MODE=false - AUTOCONFIGURE_LX_FILE=/app/var/run/lxfile volumes: # If you aren't on a RaspberryPi comment the line below diff --git a/lang/en.json b/lang/en.json index 638b1bf..b9ee7fa 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,5 +1,6 @@ { "slideshow_page_title": "Schedule Overview", + "slideshow_goto_player": "Go to player", "slideshow_slide_button_add": "Add a slide", "slideshow_slide_panel_active": "Active slides", "slideshow_slide_panel_inactive": "Inactive slides", @@ -56,7 +57,7 @@ "js_fleet_screen_delete_confirmation": "Are you sure?", "settings_page_title": "Settings", - "settings_variable_panel_system_variables": "System settings", + "settings_variable_panel_system_variables": "General settings", "settings_variable_panel_plugin_variables": "Plugins settings", "settings_variable_panel_th_description": "Description", "settings_variable_panel_th_value": "Value", @@ -81,6 +82,8 @@ "sysinfo_page_title": "System infos", "sysinfo_panel_button_restart": "Restart", + "sysinfo_panel_table_section_system": "System", + "sysinfo_panel_table_section_application": "Application", "sysinfo_panel_title": "Infos", "sysinfo_panel_th_attribute": "Attribute", "sysinfo_panel_th_value": "Value", @@ -115,5 +118,7 @@ "enum_animation_speed_slow": "Slow", "enum_animation_speed_normal": "Normal", "enum_animation_speed_fast": "Fast", - "enum_animation_speed_faster": "Faster" + "enum_animation_speed_faster": "Faster", + "enum_variable_section_general": "General", + "enum_variable_section_animation": "Animation" } diff --git a/lang/fr.json b/lang/fr.json index 594c66f..3a9f038 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1,5 +1,6 @@ { "slideshow_page_title": "Vue Planning", + "slideshow_goto_player": "Voir le lecteur", "slideshow_slide_button_add": "Ajouter une slide", "slideshow_slide_panel_active": "Slides actives", "slideshow_slide_panel_inactive": "Slides inactives", @@ -56,7 +57,7 @@ "js_fleet_screen_delete_confirmation": "Êtes-vous sûr ?", "settings_page_title": "Paramètres", - "settings_variable_panel_system_variables": "Paramètres système", + "settings_variable_panel_system_variables": "Paramètres généraux", "settings_variable_panel_plugin_variables": "Paramètres des plugins", "settings_variable_panel_th_description": "Description", "settings_variable_panel_th_value": "Valeur", @@ -81,6 +82,8 @@ "sysinfo_page_title": "Système", "sysinfo_panel_button_restart": "Redémarrer", + "sysinfo_panel_table_section_system": "Système", + "sysinfo_panel_table_section_application": "Application", "sysinfo_panel_title": "Informations", "sysinfo_panel_th_attribute": "Attribut", "sysinfo_panel_th_value": "Valeur", @@ -115,5 +118,7 @@ "enum_animation_speed_slow": "Lent", "enum_animation_speed_normal": "Normal", "enum_animation_speed_fast": "Rapide", - "enum_animation_speed_faster": "Très rapide" + "enum_animation_speed_faster": "Très rapide", + "enum_variable_section_general": "Général", + "enum_variable_section_animation": "Animation" } diff --git a/src/interface/ObPlugin.py b/src/interface/ObPlugin.py index 1ff951f..f377e60 100644 --- a/src/interface/ObPlugin.py +++ b/src/interface/ObPlugin.py @@ -56,9 +56,10 @@ class ObPlugin(abc.ABC): def get_plugin_variable_name(self, name: str) -> str: return "{}_{}".format(self.get_plugin_variable_prefix(), name) - def add_variable(self, name: str, value='', type: VariableType = VariableType.STRING, editable: bool = True, description: str = '', selectables: Optional[Dict[str, str]] = None, unit: Optional[VariableUnit] = None) -> Variable: + def add_variable(self, name: str, value='', section: str = '', type: VariableType = VariableType.STRING, editable: bool = True, description: str = '', selectables: Optional[Dict[str, str]] = None, unit: Optional[VariableUnit] = None) -> Variable: return self._model_store.variable().set_variable( name=self.get_plugin_variable_name(name), + section=section, value=value, type=type, editable=editable, diff --git a/src/manager/ConfigManager.py b/src/manager/ConfigManager.py index a518c45..88e2d09 100644 --- a/src/manager/ConfigManager.py +++ b/src/manager/ConfigManager.py @@ -20,7 +20,6 @@ class ConfigManager: 'port': self.DEFAULT_PORT, 'bind': '0.0.0.0', 'debug': False, - 'autoconfigure_reverse_proxy_mode': False, 'autoconfigure_lx_file': '/home/pi/.config/lxsession/LXDE-pi/autostart', 'log_file': None, 'log_level': 'INFO', @@ -47,7 +46,6 @@ class ConfigManager: parser.add_argument('--debug', '-d', default=self._CONFIG['debug'], help='Debug mode') parser.add_argument('--port', '-p', default=self._CONFIG['port'], help='Application port') parser.add_argument('--bind', '-b', default=self._CONFIG['bind'], help='Application bind address') - parser.add_argument('--autoconfigure-reverse-proxy-mode', '-r', default=self._CONFIG['autoconfigure_reverse_proxy_mode'], action='store_true', help='true if you want to use nginx on port 80') parser.add_argument('--autoconfigure-lx-file', '-x', default=self._CONFIG['autoconfigure_lx_file'], help='Path to lx autostart file') parser.add_argument('--log-file', '-lf', default=self._CONFIG['log_file'], help='Log File path') parser.add_argument('--log-level', '-ll', default=self._CONFIG['log_level'], help='Log Level') @@ -65,8 +63,6 @@ class ConfigManager: if args.debug: self._CONFIG['debug'] = args.debug - if args.autoconfigure_reverse_proxy_mode: - self._CONFIG['autoconfigure_reverse_proxy_mode'] = args.autoconfigure_reverse_proxy_mode if args.autoconfigure_lx_file: self._CONFIG['autoconfigure_lx_file'] = args.autoconfigure_lx_file if args.log_file: @@ -91,21 +87,9 @@ class ConfigManager: logging.info(f"Env var {key} has been found") def autoconfigure(self) -> None: - if self.map().get('autoconfigure_reverse_proxy_mode'): - self.autoconfigure_nginx() - if self.map().get('autoconfigure_lx_file'): self.autoconfigure_lxconf() - def autoconfigure_nginx(self) -> None: - reverse_proxy_config_file = 'system/nginx-obscreen' - with open(reverse_proxy_config_file, 'r') as file: - content = file.read() - with open(reverse_proxy_config_file, 'w') as file: - file.write(re.sub(r'proxy_pass .*?;', 'proxy_pass {};'.format(self.map().get('player_url')), content)) - - self._CONFIG['player_url'] = 'http://localhost' - def autoconfigure_lxconf(self) -> None: destination_path = self.map().get('autoconfigure_lx_file') player_url = self.map().get('player_url') diff --git a/src/manager/LangManager.py b/src/manager/LangManager.py index 1db0dbe..e2a725c 100644 --- a/src/manager/LangManager.py +++ b/src/manager/LangManager.py @@ -1,12 +1,22 @@ import json import logging +from typing import Union, Dict +from enum import Enum + +from src.utils import camel_to_snake + class LangManager: LANG_FILE = "lang/{}.json" - def __init__(self, lang: str): + def __init__(self, lang: str = "en"): + self._map = {} + self._lang = lang.lower() + self.load() + + def set_lang(self, lang): self._map = {} self._lang = lang.lower() self.load() @@ -24,5 +34,31 @@ class LangManager: def map(self) -> dict: return self._map - def get_locale(self, local_with_country: bool = False) -> str: - return "{}_{}".format(self._lang, self._lang.upper()) if local_with_country else self._lang \ No newline at end of file + def get_lang(self, local_with_country: bool = False) -> str: + return "{}_{}".format(self._lang, self._lang.upper()) if local_with_country else self._lang + + @staticmethod + def enum_to_translation_key(enum: Enum) -> str: + translation_key = str(enum) + + [classname, case] = translation_key.split('.') + return "enum_{}_{}".format( + camel_to_snake(classname), + case.lower() + ) + + def translate(self, token: Union[Enum, str]) -> Union[Dict, str]: + translation_key = str(token) + + if isinstance(token, type) and type(token).__name__ == 'EnumType': + values = {} + for enum_item in token: + tkey = self.enum_to_translation_key(enum_item) + values[enum_item.value] = self.translate(tkey) + return values + elif isinstance(token, Enum): + translation_key = self.enum_to_translation_key(token) + + map = self.map() + + return map[translation_key] if translation_key in map else translation_key \ No newline at end of file diff --git a/src/manager/ScreenManager.py b/src/manager/ScreenManager.py index d019d67..e4df958 100644 --- a/src/manager/ScreenManager.py +++ b/src/manager/ScreenManager.py @@ -3,9 +3,11 @@ from typing import Dict, Optional, List, Tuple, Union from src.model.entity.Screen import Screen from src.manager.DatabaseManager import DatabaseManager +from src.manager.LangManager import LangManager +from src.service.ModelManager import ModelManager -class ScreenManager: +class ScreenManager(ModelManager): TABLE_NAME = "fleet" TABLE_MODEL = [ @@ -16,8 +18,8 @@ class ScreenManager: "port" ] - def __init__(self, database_manager: DatabaseManager): - self._database_manager = database_manager + def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager): + super().__init__(lang_manager, database_manager) self._db = database_manager.open(self.TABLE_NAME, self.TABLE_MODEL) @staticmethod diff --git a/src/manager/SlideManager.py b/src/manager/SlideManager.py index 3dee264..7c2743e 100644 --- a/src/manager/SlideManager.py +++ b/src/manager/SlideManager.py @@ -6,9 +6,11 @@ from pysondb.errors import IdDoesNotExistError from src.model.entity.Slide import Slide from src.utils import str_to_enum, get_optional_string from src.manager.DatabaseManager import DatabaseManager +from src.manager.LangManager import LangManager +from src.service.ModelManager import ModelManager -class SlideManager: +class SlideManager(ModelManager): TABLE_NAME = "slideshow" TABLE_MODEL = [ @@ -21,8 +23,8 @@ class SlideManager: "cron_schedule" ] - def __init__(self, database_manager: DatabaseManager): - self._database_manager = database_manager + def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager): + super().__init__(lang_manager, database_manager) self._db = database_manager.open(self.TABLE_NAME, self.TABLE_MODEL) @staticmethod diff --git a/src/manager/VariableManager.py b/src/manager/VariableManager.py index de45a7d..2335c30 100644 --- a/src/manager/VariableManager.py +++ b/src/manager/VariableManager.py @@ -3,25 +3,29 @@ from typing import Dict, Optional, List, Tuple, Union from pysondb.errors import IdDoesNotExistError from src.manager.DatabaseManager import DatabaseManager +from src.manager.LangManager import LangManager +from src.service.ModelManager import ModelManager from src.model.entity.Variable import Variable from src.model.entity.Selectable import Selectable from src.model.enum.VariableType import VariableType from src.model.enum.VariableUnit import VariableUnit +from src.model.enum.VariableSection import VariableSection from src.model.enum.AnimationEntranceEffect import AnimationEntranceEffect from src.model.enum.AnimationExitEffect import AnimationExitEffect from src.model.enum.AnimationSpeed import AnimationSpeed -from src.utils import get_keys, enum_to_str +from src.utils import get_keys, enum_to_str, enum_to_dict SELECTABLE_BOOLEAN = {"1": "✅", "0": "❌"} -class VariableManager: +class VariableManager(ModelManager): TABLE_NAME = "settings" TABLE_MODEL = [ "description", "editable", "name", + "section", "plugin", "selectables", "type", @@ -29,13 +33,13 @@ class VariableManager: "value" ] - def __init__(self, database_manager: DatabaseManager): - self._database_manager = database_manager + def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager): + super().__init__(lang_manager, database_manager) self._db = database_manager.open(self.TABLE_NAME, self.TABLE_MODEL) self._var_map = {} self.reload() - def set_variable(self, name: str, value, type: VariableType, editable: bool, description: str, plugin: Optional[None] = None, selectables: Optional[Dict[str, str]] = None, unit: Optional[VariableUnit] = None) -> Variable: + def set_variable(self, name: str, value, type: VariableType, editable: bool, description: str, plugin: Optional[None] = None, selectables: Optional[Dict[str, str]] = None, unit: Optional[VariableUnit] = None, section: str = '') -> Variable: if isinstance(value, bool) and value: value = '1' elif isinstance(value, bool) and not value: @@ -46,6 +50,7 @@ class VariableManager: default_var = { "name": name, + "section": section, "value": value, "type": type.value, "editable": editable, @@ -68,6 +73,9 @@ class VariableManager: if variable.unit != default_var['unit']: self._db.update_by_id(variable.id, {"unit": default_var['unit']}) + if variable.section != default_var['section']: + self._db.update_by_id(variable.id, {"section": default_var['section']}) + if not same_selectables: self._db.update_by_id(variable.id, {"selectables": default_var['selectables']}) @@ -76,18 +84,21 @@ class VariableManager: return variable - def reload(self, lang_map: Optional[Dict] = None) -> None: + def reload(self) -> None: default_vars = [ - {"name": "lang", "value": "en", "type": VariableType.SELECT_SINGLE, "editable": True, "description": lang_map['settings_variable_desc_lang'] if lang_map else "", "selectables": {"en": "English", "fr": "French"}}, - {"name": "fleet_enabled", "value": False, "type": VariableType.BOOL, "editable": True, "description": lang_map['settings_variable_desc_fleet_enabled'] if lang_map else ""}, - {"name": "external_url", "value": "", "type": VariableType.STRING, "editable": True, "description": lang_map['settings_variable_desc_external_url'] if lang_map else ""}, - {"name": "slide_upload_limit", "value": 32 * 1024 * 1024, "unit": VariableUnit.BYTE, "type": VariableType.INT, "editable": True, "description": lang_map['settings_variable_desc_slide_upload_limit'] if lang_map else ""}, - {"name": "slide_animation_enabled", "value": False, "type": VariableType.BOOL, "editable": True, "description": lang_map['settings_variable_desc_slide_animation_enabled'] if lang_map else ""}, - {"name": "slide_animation_entrance_effect", "value": AnimationEntranceEffect.FADE_IN.value, "type": VariableType.SELECT_SINGLE, "editable": True, "description": lang_map['settings_variable_desc_slide_animation_entrance_effect'] if lang_map else "", "selectables": AnimationEntranceEffect.get_values()}, - {"name": "slide_animation_exit_effect", "value": AnimationExitEffect.NONE.value, "type": VariableType.SELECT_SINGLE, "editable": True, "description": lang_map['settings_variable_desc_slide_animation_exit_effect'] if lang_map else "", "selectables": AnimationExitEffect.get_values()}, - {"name": "slide_animation_speed", "value": AnimationSpeed.NORMAL.value, "type": VariableType.SELECT_SINGLE, "editable": True, "description": lang_map['settings_variable_desc_slide_animation_speed'] if lang_map else "", "selectables": AnimationSpeed.get_values(lang_map)}, - {"name": "last_restart", "value": time.time(), "type": VariableType.TIMESTAMP, "editable": False, "description": lang_map['settings_variable_desc_ro_editable'] if lang_map else ""}, - {"name": "last_slide_update", "value": time.time(), "type": VariableType.TIMESTAMP, "editable": False, "description": lang_map['settings_variable_desc_ro_last_slide_update'] if lang_map else ""}, + # Editable (Customizable settings) + {"name": "lang", "section": self.t(VariableSection.GENERAL), "value": "en", "type": VariableType.SELECT_SINGLE, "editable": True, "description": self.t('settings_variable_desc_lang'), "selectables": {"en": "English", "fr": "French"}}, + {"name": "fleet_enabled", "section": self.t(VariableSection.GENERAL), "value": False, "type": VariableType.BOOL, "editable": True, "description": self.t('settings_variable_desc_fleet_enabled')}, + {"name": "external_url", "section": self.t(VariableSection.GENERAL), "value": "", "type": VariableType.STRING, "editable": True, "description": self.t('settings_variable_desc_external_url')}, + {"name": "slide_upload_limit", "section": self.t(VariableSection.ANIMATION), "value": 32 * 1024 * 1024, "unit": VariableUnit.BYTE, "type": VariableType.INT, "editable": True, "description": self.t('settings_variable_desc_slide_upload_limit')}, + {"name": "slide_animation_enabled", "section": self.t(VariableSection.ANIMATION), "value": False, "type": VariableType.BOOL, "editable": True, "description": self.t('settings_variable_desc_slide_animation_enabled')}, + {"name": "slide_animation_entrance_effect", "section": self.t(VariableSection.ANIMATION), "value": AnimationEntranceEffect.FADE_IN.value, "type": VariableType.SELECT_SINGLE, "editable": True, "description": self.t('settings_variable_desc_slide_animation_entrance_effect'), "selectables": enum_to_dict(AnimationEntranceEffect)}, + {"name": "slide_animation_exit_effect", "section": self.t(VariableSection.ANIMATION), "value": AnimationExitEffect.NONE.value, "type": VariableType.SELECT_SINGLE, "editable": True, "description": self.t('settings_variable_desc_slide_animation_exit_effect'), "selectables": enum_to_dict(AnimationExitEffect)}, + {"name": "slide_animation_speed", "section": self.t(VariableSection.ANIMATION), "value": AnimationSpeed.NORMAL.value, "type": VariableType.SELECT_SINGLE, "editable": True, "description": self.t('settings_variable_desc_slide_animation_speed'), "selectables": self.t(AnimationSpeed)}, + + # Not editable (System information) + {"name": "last_restart", "value": time.time(), "type": VariableType.TIMESTAMP, "editable": False, "description": self.t('settings_variable_desc_ro_editable')}, + {"name": "last_slide_update", "value": time.time(), "type": VariableType.TIMESTAMP, "editable": False, "description": self.t('settings_variable_desc_ro_last_slide_update')}, ] for default_var in default_vars: diff --git a/src/model/entity/Variable.py b/src/model/entity/Variable.py index 56ea443..98f5b34 100644 --- a/src/model/entity/Variable.py +++ b/src/model/entity/Variable.py @@ -10,11 +10,12 @@ from src.utils import str_to_enum class Variable: - def __init__(self, name: str = '', description: str = '', type: Union[VariableType, str] = VariableType.STRING, + def __init__(self, name: str = '', section: str = '', description: str = '', type: Union[VariableType, str] = VariableType.STRING, value: Union[int, bool, str] = '', editable: bool = True, id: Optional[str] = None, plugin: Optional[str] = None, selectables: Optional[List[Selectable]] = None, unit: Optional[VariableUnit] = None): self._id = id if id else None self._name = name + self._section = section self._type = str_to_enum(type, VariableType) if isinstance(type, str) else type self._unit = str_to_enum(unit, VariableUnit) if isinstance(unit, str) else unit self._description = description @@ -46,6 +47,14 @@ class Variable: def name(self, value: str): self._name = value + @property + def section(self) -> str: + return self._section + + @section.setter + def section(self, value: str): + self._section = value + @property def type(self) -> VariableType: return self._type @@ -98,6 +107,7 @@ class Variable: return f"Variable(" \ f"id='{self.id}',\n" \ f"name='{self.name}',\n" \ + f"section='{self.section}',\n" \ f"value='{self.value}',\n" \ f"type='{self.type}',\n" \ f"unit='{self.unit}',\n" \ @@ -114,6 +124,7 @@ class Variable: return { "id": self.id, "name": self.name, + "section": self.section, "value": self.value, "type": self.type.value, "unit": self.unit.value if self.unit else None, diff --git a/src/model/enum/AnimationEntranceEffect.py b/src/model/enum/AnimationEntranceEffect.py index 024a1db..acac5d0 100755 --- a/src/model/enum/AnimationEntranceEffect.py +++ b/src/model/enum/AnimationEntranceEffect.py @@ -54,12 +54,4 @@ class AnimationEntranceEffect(Enum): SLIDE_IN_LEFT = 'slideInLeft' SLIDE_IN_RIGHT = 'slideInRight' SLIDE_IN_UP = 'slideInUp' - - @staticmethod - def get_values() -> dict: - values = {} - - for enum_item in AnimationEntranceEffect: - values[enum_item.value] = enum_item.value - - return values \ No newline at end of file + \ No newline at end of file diff --git a/src/model/enum/AnimationExitEffect.py b/src/model/enum/AnimationExitEffect.py index d5871ca..e3bcd74 100755 --- a/src/model/enum/AnimationExitEffect.py +++ b/src/model/enum/AnimationExitEffect.py @@ -56,12 +56,3 @@ class AnimationExitEffect(Enum): SLIDE_OUT_LEFT = 'slideOutLeft' SLIDE_OUT_RIGHT = 'slideOutRight' SLIDE_OUT_UP = 'slideOutUp' - - @staticmethod - def get_values() -> dict: - values = {} - - for enum_item in AnimationExitEffect: - values[enum_item.value] = enum_item.value - - return values \ No newline at end of file diff --git a/src/model/enum/AnimationSpeed.py b/src/model/enum/AnimationSpeed.py index bf52638..602bb9d 100755 --- a/src/model/enum/AnimationSpeed.py +++ b/src/model/enum/AnimationSpeed.py @@ -3,21 +3,8 @@ from enum import Enum class AnimationSpeed(Enum): - SLOWER = 'slower' - SLOW = 'slow' - NORMAL = 'normal' - FAST = 'fast' - FASTER = 'faster' - - @staticmethod - def get_values(lang_map: dict) -> dict: - if lang_map is None: - return {} - - return { - AnimationSpeed.SLOWER.value: lang_map['enum_animation_speed_slower'], # 3s - AnimationSpeed.SLOW.value: lang_map['enum_animation_speed_slow'], # 2s - AnimationSpeed.NORMAL.value: lang_map['enum_animation_speed_normal'], # 1s - AnimationSpeed.FAST.value: lang_map['enum_animation_speed_fast'], # 800ms - AnimationSpeed.FASTER.value: lang_map['enum_animation_speed_faster'] # 500ms - } + SLOWER = 'slower' # 3s + SLOW = 'slow' # 2s + NORMAL = 'normal' # 1s + FAST = 'fast' # 800ms + FASTER = 'faster' # 500ms diff --git a/src/model/enum/VariableSection.py b/src/model/enum/VariableSection.py new file mode 100644 index 0000000..38282f7 --- /dev/null +++ b/src/model/enum/VariableSection.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class VariableSection(Enum): + + GENERAL = 'general' + ANIMATION = 'animation' diff --git a/src/service/ModelManager.py b/src/service/ModelManager.py new file mode 100644 index 0000000..96dc3c2 --- /dev/null +++ b/src/service/ModelManager.py @@ -0,0 +1,23 @@ +from enum import Enum +from typing import Union, Dict + +from src.manager.LangManager import LangManager +from src.manager.DatabaseManager import DatabaseManager + + +class ModelManager: + + def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager): + self._lang_manager = lang_manager + self._database_manager = database_manager + + def t(self, token: Union[Enum, str]) -> Union[Dict, str]: + return self.lang_manager.translate(token) + + @property + def lang_manager(self) -> LangManager: + return self._lang_manager + + @property + def database_manager(self) -> DatabaseManager: + return self._database_manager diff --git a/src/service/ModelStore.py b/src/service/ModelStore.py index 5f5d6ac..b7f25cd 100644 --- a/src/service/ModelStore.py +++ b/src/service/ModelStore.py @@ -10,14 +10,22 @@ from src.manager.LoggingManager import LoggingManager class ModelStore: def __init__(self): + # Pure + self._lang_manager = LangManager() self._database_manager = DatabaseManager() - self._variable_manager = VariableManager(database_manager=self._database_manager) + + # Dynamics + self._variable_manager = VariableManager(lang_manager=self._lang_manager, database_manager=self._database_manager) + self._lang_manager.set_lang(self.variable().map().get('lang').as_string()) + + # Core self._config_manager = ConfigManager(variable_manager=self._variable_manager) self._logging_manager = LoggingManager(config_manager=self._config_manager) - self._screen_manager = ScreenManager(database_manager=self._database_manager) - self._slide_manager = SlideManager(database_manager=self._database_manager) - self._lang_manager = LangManager(lang=self.variable().map().get('lang').as_string()) - self._variable_manager.reload(lang_map=self._lang_manager.map()) + + # Model + self._screen_manager = ScreenManager(lang_manager=self._lang_manager, database_manager=self._database_manager) + self._slide_manager = SlideManager(lang_manager=self._lang_manager, database_manager=self._database_manager) + self._variable_manager.reload() def logging(self) -> LoggingManager: return self._logging_manager diff --git a/src/service/TemplateRenderer.py b/src/service/TemplateRenderer.py index 905f09f..731fdc9 100644 --- a/src/service/TemplateRenderer.py +++ b/src/service/TemplateRenderer.py @@ -20,7 +20,7 @@ class TemplateRenderer: self._render_hook = render_hook def cron_descriptor(self, expression: str, use_24hour_time_format=True) -> str: - return get_safe_cron_descriptor(expression, use_24hour_time_format, self._model_store.lang().get_locale(local_with_country=True)) + return get_safe_cron_descriptor(expression, use_24hour_time_format, self._model_store.lang().get_lang(local_with_country=True)) def get_view_globals(self) -> dict: globals = dict( diff --git a/src/utils.py b/src/utils.py index 1d7e03d..7b7f980 100644 --- a/src/utils.py +++ b/src/utils.py @@ -2,11 +2,26 @@ import re import subprocess import platform -from typing import Optional, List +from typing import Optional, List, Dict from enum import Enum from cron_descriptor import ExpressionDescriptor from cron_descriptor.Exception import FormatException, WrongArgumentException, MissingFieldException +CAMEL_CASE_TO_SNAKE_CASE_PATTERN = re.compile(r'(? Dict: + values = {} + + for enum_item in enum_class: + values[enum_item.value] = enum_item.value + + return values + + +def camel_to_snake(camel: str) -> str: + return CAMEL_CASE_TO_SNAKE_CASE_PATTERN.sub('_', camel).lower() + def is_validate_cron_date_time(expression) -> bool: pattern = re.compile(r'^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\*\s+(\d+)$') diff --git a/system/nginx-obscreen b/system/nginx-obscreen deleted file mode 100755 index 935acaa..0000000 --- a/system/nginx-obscreen +++ /dev/null @@ -1,22 +0,0 @@ -server { - listen 80 default_server; - listen [::]:80 default_server; - - server_name _; - - location / { - proxy_connect_timeout 60; - proxy_read_timeout 60; - proxy_send_timeout 60; - proxy_intercept_errors on; - proxy_http_version 1.1; - proxy_pass http://localhost:5000; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Real-IP $remote_addr; - } - - error_log /var/log/nginx/obscreen.error.log; - access_log /var/log/nginx/obscreen.access.log; -} diff --git a/version.txt b/version.txt index 7c483e8..6259340 100755 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.7 \ No newline at end of file +1.8 diff --git a/views/settings/component/table.jinja.html b/views/settings/component/table.jinja.html index 836b646..9b587fa 100644 --- a/views/settings/component/table.jinja.html +++ b/views/settings/component/table.jinja.html @@ -7,13 +7,20 @@
- {% set ns = namespace(last_plugin='') %} + {% set ns = namespace(last_section='') %} {% for variable in variables %} - {% if variable.plugin and ns.last_plugin != variable.plugin %} + {% if + variable.plugin and ns.last_section != variable.plugin + or variable.section and ns.last_section != variable.section + %}