mirror of
https://github.com/ManiMatter/decluttarr.git
synced 2026-04-18 05:54:00 +02:00
118 lines
3.3 KiB
Python
118 lines
3.3 KiB
Python
import os
|
|
from pathlib import Path
|
|
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):
|
|
"""
|
|
Check if data is read from environment 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 _load_from_env() -> dict:
|
|
"""
|
|
Load and parse config from environment variables defined in CONFIG_MAPPING.
|
|
|
|
Tries uppercase and lowercase keys, parses values as YAML,
|
|
and lowercases dictionary keys in the result.
|
|
|
|
Returns:
|
|
dict: Config sections with parsed env var values.
|
|
"""
|
|
config = {}
|
|
|
|
for section, keys in CONFIG_MAPPING.items():
|
|
section_config = {}
|
|
|
|
for key in keys:
|
|
env_key = key if os.getenv(key) is not None else key.lower()
|
|
raw_value = os.getenv(env_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):
|
|
"""Translate received 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()}
|
|
if isinstance(data, list):
|
|
return [_lowercase(item) for item in data]
|
|
# Leave strings and other types unchanged
|
|
return data
|
|
|
|
|
|
def _config_file_exists(settings):
|
|
config_path = settings.paths.config_file
|
|
return Path(config_path).exists()
|
|
|
|
|
|
def _load_from_yaml_file(settings):
|
|
"""Read config from YAML file and returns a dict."""
|
|
config_path = settings.paths.config_file
|
|
try:
|
|
with Path(config_path).open(encoding="utf-8") as file:
|
|
return yaml.safe_load(file) or {}
|
|
except yaml.YAMLError as e:
|
|
logger.error("Error reading YAML file: %s", e)
|
|
return {}
|