143 lines
3.7 KiB
Python
143 lines
3.7 KiB
Python
""" Miscellaneous Utilities """
|
|
import json
|
|
import logging
|
|
import os
|
|
import re
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from .const import DEFAULT_OVERRIDE_FILE, LOCAL_OVERRIDE_FILE
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
#
|
|
# deep_merge()
|
|
#
|
|
def deep_merge(base: dict, override: dict) -> dict:
|
|
"""Recursively merge override into base."""
|
|
result = base.copy()
|
|
|
|
for key, value in override.items():
|
|
if (
|
|
key in result
|
|
and isinstance(result[key], dict)
|
|
and isinstance(value, dict)
|
|
):
|
|
result[key] = deep_merge(result[key], value)
|
|
else:
|
|
result[key] = value
|
|
|
|
return result
|
|
|
|
|
|
#
|
|
# get_value()
|
|
# Traverse json and return the value at the end of the chain of keys.
|
|
# json - json to be traversed
|
|
# *keys - list of keys to use to retrieve the value
|
|
# default - default value to be returned if a key is missing
|
|
#
|
|
def get_value(json_input, *keys, default=None):
|
|
"""Traverse the json using keys to return the associated value, or default if invalid keys"""
|
|
|
|
j = json_input
|
|
try:
|
|
for k in keys:
|
|
j = j[k]
|
|
return j
|
|
except:
|
|
return default
|
|
|
|
|
|
#
|
|
# has_team()
|
|
#
|
|
def has_team(data, target_team_id):
|
|
"""Search for team in json data"""
|
|
|
|
for event in data.get("events", []):
|
|
for comp in event.get("competitions", []):
|
|
for competitor in comp.get("competitors", []):
|
|
if competitor.get("team", {}).get("id") == target_team_id:
|
|
return True
|
|
return False
|
|
|
|
|
|
#
|
|
# is_integer()
|
|
#
|
|
def is_integer(val):
|
|
"""Check if a value is an integer"""
|
|
|
|
try:
|
|
int(val)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
|
|
#
|
|
# load_file_overrides()
|
|
#
|
|
def load_file_overrides(hass: HomeAssistant) -> dict:
|
|
"""Thread-safe file loading utility."""
|
|
|
|
component_dir = os.path.dirname(__file__)
|
|
default_file = os.path.join(component_dir, "overrides", DEFAULT_OVERRIDE_FILE)
|
|
custom_file = hass.config.path(LOCAL_OVERRIDE_FILE)
|
|
|
|
base_data = {}
|
|
if os.path.exists(default_file):
|
|
try:
|
|
with open(default_file, "r", encoding="utf-8") as f:
|
|
base_data = json.load(f)
|
|
except json.JSONDecodeError as err:
|
|
_LOGGER.debug(
|
|
"File Override Error: Invalid JSON in %s: %s",
|
|
default_file,
|
|
err,
|
|
)
|
|
except OSError as err:
|
|
_LOGGER.debug(
|
|
"File Override Error: Unable to read %s: %s",
|
|
default_file,
|
|
err,
|
|
)
|
|
|
|
custom_data = {}
|
|
if os.path.exists(custom_file):
|
|
try:
|
|
with open(custom_file, "r", encoding="utf-8") as f:
|
|
custom_data = json.load(f)
|
|
except json.JSONDecodeError as err:
|
|
_LOGGER.warning(
|
|
"File Override Error: Invalid JSON in %s: %s",
|
|
custom_file,
|
|
err,
|
|
)
|
|
except OSError as err:
|
|
_LOGGER.debug(
|
|
"File Override Error: Unable to read %s: %s",
|
|
custom_file,
|
|
err,
|
|
)
|
|
|
|
override_data = deep_merge(base_data, custom_data)
|
|
return override_data
|
|
|
|
|
|
#
|
|
# season_slug_to_name()
|
|
#
|
|
def season_slug_to_name(slug: str) -> str:
|
|
"""Convert a season slug like '2025-26-english-premier-league' to 'English Premier League'."""
|
|
if not slug:
|
|
return ""
|
|
body = re.sub(r"^\d{4}(-\d{2})?-", "", slug)
|
|
if body == slug:
|
|
return ""
|
|
def _fmt_word(w):
|
|
# Uppercase abbreviations (no vowels, e.g. "mls", "nfl"); title-case real words
|
|
return w.upper() if w.isalpha() and not re.search(r"[aeiou]", w, re.I) else w.title()
|
|
return " ".join(_fmt_word(w) for w in body.split("-"))
|