remove autoconfigure player file + add demo mode
This commit is contained in:
parent
99d2518d92
commit
34ba9cd812
@ -1,4 +1,3 @@
|
||||
DEBUG=false
|
||||
PORT=5000
|
||||
SECRET_KEY=ANY_SECRET_KEY_HERE
|
||||
PLAYER_AUTOSTART_FILE=./var/run/play # Replace by "/dev/null" if not needed
|
||||
|
||||
@ -15,7 +15,7 @@ Obscreen is a user-friendly self-hosted digital signage tool. Manage a fleet of
|
||||
|
||||
Try it!
|
||||
|
||||
Demo Server (Location: Roubaix - France): https://demo.obscreen.io
|
||||
Demo Server (Location: Roubaix - France): [https://demo.obscreen.io](https://demo.obscreen.io?username=admin&password=admin)
|
||||
|
||||
It is a temporary live demo, all data will be deleted after 10 minutes. Sponsored by myself.
|
||||
|
||||
|
||||
@ -9,10 +9,8 @@ services:
|
||||
environment:
|
||||
- DEBUG=${DEBUG-false}
|
||||
- PORT=${PORT-5000}
|
||||
- PLAYER_AUTOSTART_FILE=/app/var/run/play
|
||||
- SECRET_KEY=${SECRET_KEY-ANY_SECRET_KEY_HERE}
|
||||
volumes:
|
||||
- .:/app
|
||||
- ${PLAYER_AUTOSTART_FILE-/dev/null}:/app/var/run/play
|
||||
ports:
|
||||
- ${PORT}:${PORT}
|
||||
@ -6,10 +6,8 @@ services:
|
||||
environment:
|
||||
- DEBUG=false
|
||||
- PORT=5000
|
||||
- PLAYER_AUTOSTART_FILE=/app/var/run/play
|
||||
- SECRET_KEY=ANY_SECRET_KEY_HERE
|
||||
volumes:
|
||||
- /dev/null:/app/var/run/play
|
||||
- ./data/db:/app/data/db
|
||||
- ./data/uploads:/app/data/uploads
|
||||
ports:
|
||||
|
||||
@ -6,10 +6,8 @@ services:
|
||||
environment:
|
||||
- DEBUG=false
|
||||
- PORT=5000
|
||||
- PLAYER_AUTOSTART_FILE=/app/var/run/play
|
||||
- SECRET_KEY=ANY_SECRET_KEY_HERE
|
||||
volumes:
|
||||
- ./var/run/play:/app/var/run/play
|
||||
- ./data/db:/app/data/db
|
||||
- ./data/uploads:/app/data/uploads
|
||||
ports:
|
||||
|
||||
@ -23,7 +23,6 @@ cd ~ && mkdir -p obscreen/data/db obscreen/data/uploads && cd obscreen
|
||||
docker run --restart=always --name obscreen --pull=always \
|
||||
-e DEBUG=false \
|
||||
-e PORT=5000 \
|
||||
-e PLAYER_AUTOSTART_FILE=/app/var/run/play \
|
||||
-e SECRET_KEY=ANY_SECRET_KEY_HERE \
|
||||
-p 5000:5000 \
|
||||
-v ./data/db:/app/data/db \
|
||||
|
||||
@ -25,14 +25,10 @@ curl -sSL get.docker.com | sh && sudo usermod -aG docker $(whoami) && logout # t
|
||||
# Prepare application data file tree
|
||||
cd ~ && mkdir -p obscreen/data/db obscreen/data/uploads && cd obscreen
|
||||
|
||||
# Prepare player autostart file
|
||||
mkdir -p var/run && touch var/run/play && chmod +x var/run/play
|
||||
|
||||
# Run the Docker container
|
||||
docker run --rm --name obscreen --pull=always \
|
||||
-e DEBUG=false \
|
||||
-e PORT=5000 \
|
||||
-e PLAYER_AUTOSTART_FILE=/app/var/run/play \
|
||||
-e SECRET_KEY=ANY_SECRET_KEY_HERE \
|
||||
-p 5000:5000 \
|
||||
-v ./data/db:/app/data/db \
|
||||
@ -52,9 +48,6 @@ docker run --rm --name obscreen --pull=always \
|
||||
# Prepare application data file tree
|
||||
cd ~ && mkdir -p obscreen/data/db obscreen/data/uploads obscreen/system && cd obscreen
|
||||
|
||||
# Prepare player autostart file
|
||||
mkdir -p var/run && touch var/run/play && chmod +x var/run/play
|
||||
|
||||
# Download docker-compose.yml
|
||||
curl https://raw.githubusercontent.com/jr-k/obscreen/master/docker-compose.yml > docker-compose.yml
|
||||
|
||||
|
||||
@ -226,6 +226,7 @@
|
||||
"basic_month_10": "October",
|
||||
"basic_month_11": "November",
|
||||
"basic_month_12": "December",
|
||||
"common_bad_file_type": "Bad file type uploaded",
|
||||
"common_restart_needed": "Please restart obscreen studio (or restart the device) for the changes to take effect",
|
||||
"common_pick_element": "Pick an element",
|
||||
"common_untitled": "<untitled>",
|
||||
@ -275,9 +276,8 @@
|
||||
"enum_variable_section_general": "1. General",
|
||||
"enum_variable_section_player_options": "2. Player options",
|
||||
"enum_variable_section_player_animation": "3. Player animation",
|
||||
"enum_variable_section_playlist": "4. Playlists",
|
||||
"enum_variable_section_fleet": "5. Fleet management",
|
||||
"enum_variable_section_security": "6. Security",
|
||||
"enum_variable_section_fleet": "4. Fleet management",
|
||||
"enum_variable_section_security": "5. Security",
|
||||
"enum_application_language_english": "English",
|
||||
"enum_application_language_french": "French",
|
||||
"enum_application_language_italian": "Italian",
|
||||
|
||||
@ -227,6 +227,7 @@
|
||||
"basic_month_10": "Octubre",
|
||||
"basic_month_11": "Noviembre",
|
||||
"basic_month_12": "Diciembre",
|
||||
"common_bad_file_type": "Tipo de archivo incorrecto cargado",
|
||||
"common_restart_needed": "Reinicie obscreen studio (o reinicie el dispositivo) para que los cambios surtan efecto",
|
||||
"common_pick_element": "Elige un elemento",
|
||||
"common_untitled": "<sin-título>",
|
||||
@ -276,9 +277,8 @@
|
||||
"enum_variable_section_general": "1. General",
|
||||
"enum_variable_section_player_options": "2. Opciones del reproductor",
|
||||
"enum_variable_section_player_animation": "3. Animación del reproductor",
|
||||
"enum_variable_section_playlist": "4. Playlist",
|
||||
"enum_variable_section_fleet": "5. Gestión de flota",
|
||||
"enum_variable_section_security": "6. Seguridad",
|
||||
"enum_variable_section_fleet": "4. Gestión de flota",
|
||||
"enum_variable_section_security": "5. Seguridad",
|
||||
"enum_application_language_english": "Inglés",
|
||||
"enum_application_language_french": "Francés",
|
||||
"enum_application_language_italian": "Italiano",
|
||||
|
||||
@ -228,6 +228,7 @@
|
||||
"basic_month_10": "Octobre",
|
||||
"basic_month_11": "Novembre",
|
||||
"basic_month_12": "Décembre",
|
||||
"common_bad_file_type": "Type de fichier uploadé incorrect",
|
||||
"common_restart_needed": "Veuillez redémarrer obscreen studio (ou redémarrer l'appareil) pour que les changements soient pris en compte",
|
||||
"common_pick_element": "Choisissez un élément",
|
||||
"common_untitled": "<sans-titre>",
|
||||
@ -277,9 +278,8 @@
|
||||
"enum_variable_section_general": "1. Général",
|
||||
"enum_variable_section_player_options": "2. Options du lecteur",
|
||||
"enum_variable_section_player_animation": "3. Animation du lecteur",
|
||||
"enum_variable_section_playlist": "4. Playlists",
|
||||
"enum_variable_section_fleet": "5. Gestion de flotte",
|
||||
"enum_variable_section_security": "6. Sécurité",
|
||||
"enum_variable_section_fleet": "4. Gestion de flotte",
|
||||
"enum_variable_section_security": "5. Sécurité",
|
||||
"enum_application_language_english": "Anglais",
|
||||
"enum_application_language_french": "Français",
|
||||
"enum_application_language_italian": "Italien",
|
||||
|
||||
@ -227,6 +227,7 @@
|
||||
"basic_month_10": "Ottobre",
|
||||
"basic_month_11": "Novembre",
|
||||
"basic_month_12": "Dicembre",
|
||||
"common_bad_file_type": "Tipo di file caricato non valido",
|
||||
"common_restart_needed": "Riavvia obscreen studio (o riavvia il dispositivo) affinché le modifiche abbiano effetto",
|
||||
"common_pick_element": "Scegli un elemento",
|
||||
"common_untitled": "<senza-titolo>",
|
||||
@ -276,9 +277,8 @@
|
||||
"enum_variable_section_general": "1. Generale",
|
||||
"enum_variable_section_player_options": "2. Opzioni monitor",
|
||||
"enum_variable_section_player_animation": "3. Animazioni monitor",
|
||||
"enum_variable_section_playlist": "4. Playlist",
|
||||
"enum_variable_section_fleet": "5. Gestione panoramica",
|
||||
"enum_variable_section_security": "6. Sicurezza",
|
||||
"enum_variable_section_fleet": "4. Gestione panoramica",
|
||||
"enum_variable_section_security": "5. Sicurezza",
|
||||
"enum_application_language_english": "Inglese",
|
||||
"enum_application_language_french": "Francese",
|
||||
"enum_application_language_italian": "Italiano",
|
||||
|
||||
@ -48,7 +48,7 @@ class AuthController(ObController):
|
||||
return render_template(
|
||||
'auth/login.jinja.html',
|
||||
login_error=login_error,
|
||||
last_username=request.form['username'] if 'username' in request.form else ''
|
||||
last_username=request.form['username'] if 'username' in request.form else None
|
||||
)
|
||||
|
||||
def logout(self):
|
||||
|
||||
@ -63,8 +63,11 @@ class ContentController(ObController):
|
||||
|
||||
def slideshow_content_add(self):
|
||||
working_folder_path, working_folder = self.get_working_folder()
|
||||
route_args = {
|
||||
"path": working_folder_path,
|
||||
}
|
||||
|
||||
self._model_store.content().add_form_raw(
|
||||
content = self._model_store.content().add_form_raw(
|
||||
name=request.form['name'],
|
||||
type=str_to_enum(request.form['type'], ContentType),
|
||||
request_files=request.files,
|
||||
@ -73,7 +76,10 @@ class ContentController(ObController):
|
||||
folder_id=working_folder.id if working_folder else None
|
||||
)
|
||||
|
||||
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||
if not content:
|
||||
route_args["error"] = 'common_bad_file_type'
|
||||
|
||||
return redirect(url_for('slideshow_content_list', **route_args))
|
||||
|
||||
def slideshow_content_upload_bulk(self):
|
||||
working_folder_path, working_folder = self.get_working_folder()
|
||||
|
||||
@ -64,6 +64,7 @@ class PlayerController(ObController):
|
||||
return render_template(
|
||||
'player/default.jinja.html',
|
||||
interfaces=[iface['ip_address'] for iface in get_network_interfaces()],
|
||||
external_url=self._model_store.variable().get_one_by_name('external_url').as_string().strip(),
|
||||
time_with_seconds=self._model_store.variable().get_one_by_name('default_slide_time_with_seconds'),
|
||||
noplaylist=request.args.get('noplaylist', '0') == '1'
|
||||
)
|
||||
|
||||
@ -68,5 +68,6 @@ class SysinfoController(ObController):
|
||||
|
||||
def sysinfo_get_ipaddr(self):
|
||||
return jsonify({
|
||||
'external_url': self._model_store.variable().get_one_by_name('external_url').as_string().strip(),
|
||||
'interfaces': [iface['ip_address'] for iface in get_network_interfaces()]
|
||||
})
|
||||
|
||||
@ -1,33 +1,27 @@
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
|
||||
from src.manager.VariableManager import VariableManager
|
||||
from src.util.utils import am_i_in_docker
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
class ConfigManager:
|
||||
|
||||
DEFAULT_PORT = 5000
|
||||
DEFAULT_PLAYER_AUTOSTART_PATH = './var/run/play'
|
||||
VERSION_FILE = 'version.txt'
|
||||
|
||||
def __init__(self, variable_manager: VariableManager):
|
||||
self._variable_manager = variable_manager
|
||||
def __init__(self):
|
||||
self._CONFIG = {
|
||||
'version': None,
|
||||
'demo': False,
|
||||
'port': self.DEFAULT_PORT,
|
||||
'bind': '0.0.0.0',
|
||||
'debug': False,
|
||||
'player_autostart_file': self.DEFAULT_PLAYER_AUTOSTART_PATH,
|
||||
'log_file': None,
|
||||
'log_level': 'INFO',
|
||||
'log_stdout': True,
|
||||
'secret_key': 'ANY_SECRET_KEY_HERE',
|
||||
'player_url': 'http://localhost:{}'.format(self.DEFAULT_PORT)
|
||||
}
|
||||
|
||||
self.load_version()
|
||||
@ -36,8 +30,6 @@ class ConfigManager:
|
||||
|
||||
self._CONFIG['port'] = self._CONFIG['port'] if self._CONFIG['port'] else self.DEFAULT_PORT
|
||||
|
||||
self.autoconfigure()
|
||||
|
||||
if self.map().get('debug'):
|
||||
logging.debug(self._CONFIG)
|
||||
|
||||
@ -50,10 +42,10 @@ class ConfigManager:
|
||||
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('--secret-key', '-s', default=self._CONFIG['secret_key'], help='Application secret key (any random string)')
|
||||
parser.add_argument('--player-autostart-file', '-x', default=self._CONFIG['player_autostart_file'], help='Path to player 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')
|
||||
parser.add_argument('--log-stdout', '-ls', default=self._CONFIG['log_stdout'], action='store_true', help='Log to standard output')
|
||||
parser.add_argument('--demo', '-o', default=self._CONFIG['demo'], help='Demo mode to showcase obscreen in a sandbox')
|
||||
parser.add_argument('--version', '-v', default=None, action='store_true', help='Get version number')
|
||||
|
||||
return parser.parse_args()
|
||||
@ -67,8 +59,8 @@ class ConfigManager:
|
||||
|
||||
if args.debug:
|
||||
self._CONFIG['debug'] = args.debug
|
||||
if args.player_autostart_file:
|
||||
self._CONFIG['player_autostart_file'] = args.player_autostart_file
|
||||
if args.demo:
|
||||
self._CONFIG['demo'] = args.demo
|
||||
if args.log_file:
|
||||
self._CONFIG['log_file'] = args.log_file
|
||||
if args.secret_key:
|
||||
@ -91,60 +83,3 @@ class ConfigManager:
|
||||
value = True
|
||||
self._CONFIG[key.lower()] = value
|
||||
logging.info(f"Env var {key} has been found")
|
||||
|
||||
def autoconfigure(self) -> None:
|
||||
self.autoconfigure_player_url()
|
||||
|
||||
if self.map().get('player_autostart_file'):
|
||||
self.autoconfigure_player_autostart_file()
|
||||
|
||||
|
||||
def autoconfigure_player_url(self) -> str:
|
||||
self._CONFIG['player_url'] = 'http://localhost:{}'.format(self.map().get('port'))
|
||||
|
||||
return self._CONFIG['player_url']
|
||||
|
||||
def autoconfigure_player_autostart_file(self) -> None:
|
||||
path = self.map().get('player_autostart_file')
|
||||
in_docker = am_i_in_docker()
|
||||
player_autostart_path = self.DEFAULT_PLAYER_AUTOSTART_PATH if in_docker else path
|
||||
|
||||
if os.path.isdir(path) or not os.path.exists(path):
|
||||
if not in_docker:
|
||||
open(player_autostart_path, 'a').close()
|
||||
else:
|
||||
logging.error(
|
||||
"Player autostart file {} doesn't exist on your server'\n".format(
|
||||
player_autostart_path
|
||||
)
|
||||
)
|
||||
sys.exit(1)
|
||||
else:
|
||||
logging.info("Overriding player autostart file {}".format(player_autostart_path))
|
||||
|
||||
player_url = self.map().get('player_url')
|
||||
os.makedirs(os.path.dirname(player_autostart_path), exist_ok=True)
|
||||
xenv_presets = """#!/bin/bash
|
||||
|
||||
# Disable screensaver and DPMS
|
||||
xset s off
|
||||
xset -dpms
|
||||
xset s noblank
|
||||
|
||||
# Start unclutter to hide the mouse cursor
|
||||
unclutter -display :0 -noevents -grab &
|
||||
|
||||
# Modify Chromium preferences to avoid restore messages
|
||||
mkdir -p __HOME__/.config/chromium/Default 2>/dev/null
|
||||
touch __HOME__/.config/chromium/Default/Preferences
|
||||
sed -i 's/"exited_cleanly": false/"exited_cleanly": true/' __HOME__/.config/chromium/Default/Preferences
|
||||
|
||||
RESOLUTION=$(DISPLAY=:0 xrandr | grep '*' | awk '{print $1}')
|
||||
WIDTH=$(echo $RESOLUTION | cut -d 'x' -f 1)
|
||||
HEIGHT=$(echo $RESOLUTION | cut -d 'x' -f 2)
|
||||
|
||||
# Start Chromium in kiosk mode
|
||||
chromium-browser --disable-features=Translate --ignore-certificate-errors --disable-web-security --disable-restore-session-state --autoplay-policy=no-user-gesture-required --start-maximized --allow-running-insecure-content --remember-cert-error-decisions --noerrdialogs --kiosk --incognito --window-position=0,0 --window-size=${WIDTH},${HEIGHT} --display=:0 __PLAYER_URL__
|
||||
""".replace('__PLAYER_URL__', player_url).replace('__HOME__', os.environ['HOME'])
|
||||
with open(player_autostart_path, 'w') as file:
|
||||
file.write(xenv_presets)
|
||||
|
||||
@ -177,6 +177,11 @@ class ContentManager(ModelManager):
|
||||
if not object or object.filename == '':
|
||||
return None
|
||||
|
||||
guessed_type = ContentType.guess_content_type_file(object)
|
||||
|
||||
if not guessed_type or guessed_type != type:
|
||||
return None
|
||||
|
||||
if object:
|
||||
object.seek(0)
|
||||
object_name = randomize_filename(object.filename)
|
||||
|
||||
@ -5,6 +5,7 @@ from typing import Dict, Optional, List, Tuple, Union
|
||||
|
||||
from src.manager.DatabaseManager import DatabaseManager
|
||||
from src.manager.LangManager import LangManager
|
||||
from src.manager.ConfigManager import ConfigManager
|
||||
from src.manager.UserManager import UserManager
|
||||
from src.model.entity.Variable import Variable
|
||||
from src.model.entity.Selectable import Selectable
|
||||
@ -38,9 +39,10 @@ class VariableManager:
|
||||
"value TEXT"
|
||||
]
|
||||
|
||||
def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager, user_manager: UserManager):
|
||||
def __init__(self, lang_manager: LangManager, database_manager: DatabaseManager, user_manager: UserManager, config_manager: ConfigManager):
|
||||
self._lang_manager = lang_manager
|
||||
self._user_manager = user_manager
|
||||
self._config_manager = config_manager
|
||||
self._db = database_manager.open(self.TABLE_NAME, self.TABLE_MODEL)
|
||||
self._var_map = {}
|
||||
self.reload()
|
||||
@ -94,6 +96,9 @@ class VariableManager:
|
||||
if variable.refresh_player != default_var['refresh_player']:
|
||||
self._db.update_by_id(self.TABLE_NAME, variable.id, {"refresh_player": default_var['refresh_player']})
|
||||
|
||||
if variable.editable != default_var['editable']:
|
||||
self._db.update_by_id(self.TABLE_NAME, variable.id, {"editable": default_var['editable']})
|
||||
|
||||
if not same_selectables_keys or not same_selectables_label:
|
||||
self._db.update_by_id(self.TABLE_NAME, variable.id, {"selectables": default_var['selectables']})
|
||||
|
||||
@ -103,13 +108,15 @@ class VariableManager:
|
||||
return variable
|
||||
|
||||
def reload(self) -> None:
|
||||
demo = self._config_manager.map().get('demo')
|
||||
|
||||
default_vars = [
|
||||
# Editable (Customizable settings)
|
||||
|
||||
### General
|
||||
{"name": "lang", "section": self.t(VariableSection.GENERAL), "value": "en", "type": VariableType.SELECT_SINGLE, "editable": True, "description": self.t('settings_variable_desc_lang'), "selectables": self.t(ApplicationLanguage), "refresh_player": False},
|
||||
{"name": "external_url", "section": self.t(VariableSection.GENERAL), "value": "", "type": VariableType.STRING, "editable": True, "description": self.t('settings_variable_desc_external_url'), "refresh_player": False},
|
||||
{"name": "slide_upload_limit", "section": self.t(VariableSection.GENERAL), "value": 32, "unit": VariableUnit.MEGABYTE, "type": VariableType.INT, "editable": True, "description": self.t('settings_variable_desc_slide_upload_limit'), "refresh_player": False},
|
||||
{"name": "external_url", "section": self.t(VariableSection.GENERAL), "value": "", "type": VariableType.STRING, "editable": False if demo else True, "description": self.t('settings_variable_desc_external_url'), "refresh_player": False},
|
||||
{"name": "slide_upload_limit", "section": self.t(VariableSection.GENERAL), "value": 32, "unit": VariableUnit.MEGABYTE, "type": VariableType.INT, "editable": False if demo else True, "description": self.t('settings_variable_desc_slide_upload_limit'), "refresh_player": False},
|
||||
{"name": "dark_mode", "section": self.t(VariableSection.GENERAL), "value": True, "type": VariableType.BOOL, "editable": True, "description": self.t('settings_variable_desc_dark_mode'), "refresh_player": False},
|
||||
|
||||
### Player Options
|
||||
@ -209,6 +216,16 @@ class VariableManager:
|
||||
return self.get_by(query="editable = 0", sort="name")
|
||||
|
||||
def update_form(self, id: int, value: Union[int, bool, str]) -> None:
|
||||
variable = self.get(id)
|
||||
|
||||
if not variable:
|
||||
if var.name in self._var_map:
|
||||
del self._var_map[var.name]
|
||||
return None
|
||||
|
||||
if not variable.editable:
|
||||
return None
|
||||
|
||||
self._db.update_by_id(self.TABLE_NAME, id, {"value": value})
|
||||
var = self.get_one_by("id = {}".format(id))
|
||||
self._var_map[var.name] = var
|
||||
|
||||
@ -19,19 +19,19 @@ class ModelStore:
|
||||
def __init__(self, get_plugins: Dict):
|
||||
self._get_plugins = get_plugins
|
||||
|
||||
# Core
|
||||
self._config_manager = ConfigManager()
|
||||
self._logging_manager = LoggingManager(config_manager=self._config_manager)
|
||||
|
||||
# Pure
|
||||
self._lang_manager = LangManager()
|
||||
self._database_manager = DatabaseManager()
|
||||
|
||||
# Dynamics
|
||||
self._user_manager = UserManager(lang_manager=self._lang_manager, database_manager=self._database_manager, on_user_delete=self.on_user_delete)
|
||||
self._variable_manager = VariableManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager)
|
||||
self._variable_manager = VariableManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, config_manager=self._config_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)
|
||||
|
||||
# Model
|
||||
self._folder_manager = FolderManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
self._node_player_manager = NodePlayerManager(lang_manager=self._lang_manager, database_manager=self._database_manager, user_manager=self._user_manager, variable_manager=self._variable_manager)
|
||||
|
||||
@ -29,13 +29,13 @@
|
||||
<div class="form-group">
|
||||
<label for="password">{{ l.login_form_username }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="username" required="required" value="{{ last_username }}" />
|
||||
<input type="text" name="username" required="required" value="{{ last_username|d(request.args.get('username', ''), True) }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">{{ l.login_form_password }}</label>
|
||||
<div class="widget">
|
||||
<input type="password" name="password" required="required"/>
|
||||
<input type="password" name="password" required="required" value="{{ request.args.get('password', '') }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions actions-center">
|
||||
|
||||
@ -52,9 +52,9 @@
|
||||
{% if ro_variable.value %}
|
||||
{% if ro_variable.type.value == 'bool' %}
|
||||
{% if ro_variable.display() %}
|
||||
✅
|
||||
<i class="fa fa-check alert alert-success alert-icon icon-value"></i>
|
||||
{% else %}
|
||||
❌
|
||||
<i class="fa fa-times alert alert-error alert-icon icon-value"></i>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ ro_variable.display() }}
|
||||
@ -78,9 +78,9 @@
|
||||
<td class="description">{{ env_key.replace('_',' ')|capitalize }}</td>
|
||||
<td class="value">
|
||||
{% if env_value == true %}
|
||||
✅
|
||||
<i class="fa fa-check alert alert-success alert-icon icon-value"></i>
|
||||
{% elif env_value == false %}
|
||||
❌
|
||||
<i class="fa fa-times alert alert-error alert-icon icon-value"></i>
|
||||
{% elif env_value == none %}
|
||||
<span class="empty">{{ l.common_empty }}</span>
|
||||
{% else %}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
const time_with_seconds = {{ 'true' if time_with_seconds.as_bool() else 'false' }};
|
||||
let external_url = '{{ external_url }}';
|
||||
|
||||
function updateTime() {
|
||||
const date = new Date();
|
||||
@ -13,11 +14,11 @@
|
||||
const month = date.getMonth();
|
||||
const year = date.getFullYear();
|
||||
const day = date.getDay();
|
||||
const dayLabels = ["{{l.basic_day_7}}", "{{l.basic_day_1}}", "{{l.basic_day_2}}", "{{l.basic_day_3}}", "{{l.basic_day_4}}", "{{l.basic_day_5}}", "{{l.basic_day_6}}"];
|
||||
const monthLabels = ["{{l.basic_month_1}}", "{{l.basic_month_2}}", "{{l.basic_month_3}}", "{{l.basic_month_4}}", "{{l.basic_month_5}}", "{{l.basic_month_6}}", "{{l.basic_month_7}}", "{{l.basic_month_8}}", "{{l.basic_month_9}}", "{{l.basic_month_10}}", "{{l.basic_month_11}}", "{{l.basic_month_12}}"];
|
||||
const day_labels = ["{{l.basic_day_7}}", "{{l.basic_day_1}}", "{{l.basic_day_2}}", "{{l.basic_day_3}}", "{{l.basic_day_4}}", "{{l.basic_day_5}}", "{{l.basic_day_6}}"];
|
||||
const month_labels = ["{{l.basic_month_1}}", "{{l.basic_month_2}}", "{{l.basic_month_3}}", "{{l.basic_month_4}}", "{{l.basic_month_5}}", "{{l.basic_month_6}}", "{{l.basic_month_7}}", "{{l.basic_month_8}}", "{{l.basic_month_9}}", "{{l.basic_month_10}}", "{{l.basic_month_11}}", "{{l.basic_month_12}}"];
|
||||
|
||||
const timeLabel = hours + ":" + minutes + (time_with_seconds ? ':' + seconds : '');
|
||||
const dateLabel = dayLabels[day] + " " + dayInMonth + " " + monthLabels[month] + " " + year;
|
||||
const dateLabel = day_labels[day] + " " + dayInMonth + " " + month_labels[month] + " " + year;
|
||||
|
||||
document.getElementById('time').innerHTML = timeLabel;
|
||||
document.getElementById('date').innerHTML = dateLabel;
|
||||
@ -32,8 +33,9 @@
|
||||
xhr.open("GET", "{{ url_for('sysinfo_get_ipaddr') }}", true);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
const jsonResponse = JSON.parse(xhr.responseText);
|
||||
setIps(jsonResponse.interfaces)
|
||||
const json_response = JSON.parse(xhr.responseText);
|
||||
external_url = json_response.external_url;
|
||||
setIps(json_response.interfaces)
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
@ -51,6 +53,8 @@
|
||||
.ipaddr a { text-decoration: none; font-weight: normal; font-size: 1.2em; color: #666; transition: .1s ease-in all; display:block; flex-direction:row; align-self: stretch; flex: 1; text-align: center; margin: 0 20px; border-radius: 6px; padding: 10px 0; }
|
||||
.ipaddr a span { color: white; font-size: 1.2em; }
|
||||
.ipaddr a:hover { color: #fff; background: #017BFF; }
|
||||
.ipaddr a.external { color: #017BFF; }
|
||||
.ipaddr a.external:hover { background: #FFFFFF; }
|
||||
#hidden-container { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
@ -82,21 +86,29 @@
|
||||
Object.assign($ipaddrs, { className: 'ipaddrs'});
|
||||
$container.appendChild($ipaddrs);
|
||||
|
||||
if (external_url.length) {
|
||||
addLink($ipaddrs, external_url, external_url, 'external');
|
||||
}
|
||||
|
||||
for (let i = 0; i < ips.length; i++) {
|
||||
addIp(ips[i], $ipaddrs);
|
||||
addIp($ipaddrs, ips[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addIp = function(ip, $container) {
|
||||
const addIp = function($container, ip) {
|
||||
const href_label = manage_url_template.replace('%ipaddr%', '<span>'+ip+'</span>');
|
||||
const href = manage_url_template.replace('%ipaddr%', ip);
|
||||
const link = '<a href="' + href + '" target="_blank">' + href_label + '</a>';
|
||||
addLink($container, href_label, href, 'ip');
|
||||
};
|
||||
|
||||
const addLink = function($container, href_label, href, classname) {
|
||||
const link = '<a href="' + href + '" target="_blank" class="' + classname + '">' + href_label + '</a>';
|
||||
const $ipaddr = document.createElement('li');
|
||||
Object.assign($ipaddr, { className: 'ipaddr'});
|
||||
$ipaddr.innerHTML = link;
|
||||
$container.appendChild($ipaddr);
|
||||
}
|
||||
};
|
||||
|
||||
setIps(interfaces);
|
||||
</script>
|
||||
|
||||
@ -95,6 +95,11 @@
|
||||
<i class="fa fa-warning icon-left"></i>
|
||||
{{ l.slideshow_content_referenced_in_slide_error }}
|
||||
</div>
|
||||
{% elif request.args.get('error') %}
|
||||
<div class="alert alert-danger">
|
||||
<i class="fa fa-warning icon-left"></i>
|
||||
{{ t(request.args.get('error')) }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger hidden"></div>
|
||||
{% endif %}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user