mirror of
https://github.com/ManiMatter/decluttarr.git
synced 2026-04-18 07:54:05 +02:00
Code Rewrite to support multi instances
This commit is contained in:
138
src/settings/_user_config.py
Normal file
138
src/settings/_user_config.py
Normal file
@@ -0,0 +1,138 @@
|
||||
import os
|
||||
import yaml
|
||||
from src.utils.log_setup import logger
|
||||
|
||||
CONFIG_MAPPING = {
|
||||
"general": [
|
||||
"LOG_LEVEL",
|
||||
"TEST_RUN",
|
||||
"TIMER",
|
||||
"SSL_VERIFICATION",
|
||||
"IGNORED_DOWNLOAD_CLIENTS",
|
||||
],
|
||||
"job_defaults": [
|
||||
"MAX_STRIKES",
|
||||
"MIN_DAYS_BETWEEN_SEARCHES",
|
||||
"MAX_CONCURRENT_SEARCHES",
|
||||
],
|
||||
"jobs": [
|
||||
"REMOVE_BAD_FILES",
|
||||
"REMOVE_FAILED_DOWNLOADS",
|
||||
"REMOVE_FAILED_IMPORTS",
|
||||
"REMOVE_METADATA_MISSING",
|
||||
"REMOVE_MISSING_FILES",
|
||||
"REMOVE_ORPHANS",
|
||||
"REMOVE_SLOW",
|
||||
"REMOVE_STALLED",
|
||||
"REMOVE_UNMONITORED",
|
||||
"SEARCH_UNMET_CUTOFF_CONTENT",
|
||||
"SEARCH_MISSING_CONTENT",
|
||||
],
|
||||
"instances": ["SONARR", "RADARR", "READARR", "LIDARR", "WHISPARR"],
|
||||
"download_clients": ["QBITTORRENT"],
|
||||
}
|
||||
|
||||
|
||||
def get_user_config(settings):
|
||||
"""Checks if data is read from enviornment variables, or from yaml file.
|
||||
|
||||
Reads from environment variables if in docker, unless in docker-compose "USE_CONFIG_YAML" is set to true.
|
||||
Then the config file is read.
|
||||
"""
|
||||
config = {}
|
||||
if _config_file_exists(settings):
|
||||
config = _load_from_yaml_file(settings)
|
||||
settings.envs.use_config_yaml = True
|
||||
elif settings.envs.in_docker:
|
||||
config = _load_from_env()
|
||||
# Ensure all top-level keys exist, even if empty
|
||||
for section in CONFIG_MAPPING:
|
||||
if config.get(section) is None:
|
||||
config[section] = {}
|
||||
return config
|
||||
|
||||
|
||||
def _parse_env_var(key: str) -> dict | list | str | int | None:
|
||||
"""Helper function to parse one setting input key"""
|
||||
raw_value = os.getenv(key)
|
||||
if raw_value is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
parsed = yaml.safe_load(raw_value)
|
||||
return _lowercase(parsed)
|
||||
except yaml.YAMLError as e:
|
||||
logger.error(f"Failed to parse environment variable {key} as YAML:\n{e}")
|
||||
return {}
|
||||
|
||||
|
||||
def _load_section(keys: list[str]) -> dict:
|
||||
"""Helper function to parse one section of expected config"""
|
||||
section_config = {}
|
||||
for key in keys:
|
||||
parsed = _parse_env_var(key)
|
||||
if parsed is not None:
|
||||
section_config[key.lower()] = parsed
|
||||
return section_config
|
||||
|
||||
|
||||
def _load_from_env() -> dict:
|
||||
"""Main function to load settings from env"""
|
||||
config = {}
|
||||
for section, keys in CONFIG_MAPPING.items():
|
||||
config[section] = _load_section(keys)
|
||||
return config
|
||||
|
||||
|
||||
def _load_from_env() -> dict:
|
||||
config = {}
|
||||
|
||||
for section, keys in CONFIG_MAPPING.items():
|
||||
section_config = {}
|
||||
|
||||
for key in keys:
|
||||
raw_value = os.getenv(key)
|
||||
if raw_value is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
parsed_value = yaml.safe_load(raw_value)
|
||||
parsed_value = _lowercase(parsed_value)
|
||||
except yaml.YAMLError as e:
|
||||
logger.error(
|
||||
f"Failed to parse environment variable {key} as YAML:\n{e}"
|
||||
)
|
||||
parsed_value = {}
|
||||
section_config[key.lower()] = parsed_value
|
||||
|
||||
config[section] = section_config
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def _lowercase(data):
|
||||
"""Translates recevied keys (for instance setting-keys of jobs) to lower case"""
|
||||
if isinstance(data, dict):
|
||||
return {str(k).lower(): _lowercase(v) for k, v in data.items()}
|
||||
elif isinstance(data, list):
|
||||
return [_lowercase(item) for item in data]
|
||||
else:
|
||||
# Leave strings and other types unchanged
|
||||
return data
|
||||
|
||||
|
||||
def _config_file_exists(settings):
|
||||
config_path = settings.paths.config_file
|
||||
return os.path.exists(config_path)
|
||||
|
||||
|
||||
def _load_from_yaml_file(settings):
|
||||
"""Reads config from YAML file and returns a dict."""
|
||||
config_path = settings.paths.config_file
|
||||
try:
|
||||
with open(config_path, "r", encoding="utf-8") as file:
|
||||
config = yaml.safe_load(file) or {}
|
||||
return config
|
||||
except yaml.YAMLError as e:
|
||||
logger.error("Error reading YAML file: %s", e)
|
||||
return {}
|
||||
Reference in New Issue
Block a user