2025-07-22 19:32:19 +03:00
|
|
|
import json
|
|
|
|
import os
|
2025-07-25 23:32:56 +03:00
|
|
|
from typing import Dict, List, Literal, Mapping, Any, TypedDict
|
2025-07-22 19:32:19 +03:00
|
|
|
from modules.keys import Language
|
2025-07-23 10:19:08 +03:00
|
|
|
import logging
|
2025-07-22 19:32:19 +03:00
|
|
|
import copy
|
|
|
|
|
|
|
|
logger = logging.getLogger("goober")
|
|
|
|
|
2025-07-26 00:10:31 +03:00
|
|
|
ActivityType = Literal["listening", "playing", "streaming", "competing", "watching"]
|
|
|
|
|
2025-07-27 12:24:51 +03:00
|
|
|
class SyncHub(TypedDict):
|
|
|
|
url: str
|
|
|
|
enabled: bool
|
2025-07-26 00:10:31 +03:00
|
|
|
|
|
|
|
class Activity(TypedDict):
|
|
|
|
content: str
|
|
|
|
type: ActivityType
|
|
|
|
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
class MiscBotOptions(TypedDict):
|
|
|
|
ping_line: str
|
2025-07-26 00:10:31 +03:00
|
|
|
activity: Activity
|
2025-07-22 19:32:19 +03:00
|
|
|
positive_gifs: List[str]
|
|
|
|
block_profanity: bool
|
|
|
|
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
class BotSettings(TypedDict):
|
|
|
|
prefix: str
|
|
|
|
owner_ids: List[int]
|
|
|
|
blacklisted_users: List[int]
|
|
|
|
user_training: bool
|
|
|
|
allow_show_mem_command: bool
|
|
|
|
react_to_messages: bool
|
|
|
|
misc: MiscBotOptions
|
|
|
|
enabled_cogs: List[str]
|
|
|
|
active_memory: str
|
2025-07-27 12:24:51 +03:00
|
|
|
sync_hub: SyncHub
|
2025-07-22 19:32:19 +03:00
|
|
|
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
class SettingsType(TypedDict):
|
|
|
|
bot: BotSettings
|
|
|
|
locale: Language
|
|
|
|
name: str
|
|
|
|
auto_update: bool
|
|
|
|
disable_checks: bool
|
|
|
|
splash_text_loc: str
|
2025-07-25 23:17:45 +03:00
|
|
|
cog_settings: Dict[str, Mapping[Any, Any]]
|
2025-07-22 19:32:19 +03:00
|
|
|
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-23 15:42:13 +03:00
|
|
|
class AdminLogEvent(TypedDict):
|
|
|
|
messageId: int
|
|
|
|
author: int
|
|
|
|
target: str | int
|
|
|
|
action: Literal["del", "add", "set"]
|
|
|
|
change: Literal["owner_ids", "blacklisted_users", "enabled_cogs"]
|
|
|
|
|
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
class Settings:
|
|
|
|
def __init__(self) -> None:
|
2025-07-23 15:42:13 +03:00
|
|
|
global instance
|
|
|
|
instance = self
|
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
self.path: str = os.path.join(".", "settings", "settings.json")
|
|
|
|
|
|
|
|
if not os.path.exists(self.path):
|
2025-07-26 00:12:43 +03:00
|
|
|
logger.critical(
|
|
|
|
f"Missing settings file from {self.path}! Did you forget to copy settings.example.json?"
|
|
|
|
)
|
2025-07-22 19:32:19 +03:00
|
|
|
raise ValueError("settings.json file does not exist!")
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
self.settings: SettingsType
|
|
|
|
self.original_settings: SettingsType
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
with open(self.path, "r") as f:
|
|
|
|
self.__kv_store: dict = json.load(f)
|
2025-07-23 10:19:08 +03:00
|
|
|
|
|
|
|
self.settings = SettingsType(self.__kv_store) # type: ignore
|
2025-07-22 19:32:19 +03:00
|
|
|
self.original_settings = copy.deepcopy(self.settings)
|
|
|
|
|
2025-07-23 15:42:13 +03:00
|
|
|
self.log_path: str = os.path.join(".", "settings", "admin_logs.json")
|
|
|
|
|
2025-07-26 00:10:31 +03:00
|
|
|
self.migrate()
|
|
|
|
|
|
|
|
def migrate(self):
|
|
|
|
active_song: str | None = (
|
|
|
|
self.settings.get("bot", {}).get("misc", {}).get("active_song")
|
|
|
|
)
|
|
|
|
|
|
|
|
if active_song:
|
|
|
|
logger.warning("Found deprecated active_song, migrating")
|
|
|
|
|
|
|
|
self.settings["bot"]["misc"]["activity"] = {
|
|
|
|
"content": active_song,
|
|
|
|
"type": "listening",
|
|
|
|
}
|
|
|
|
|
|
|
|
del self.settings["bot"]["misc"]["active_song"] # type: ignore
|
|
|
|
|
2025-07-27 12:24:51 +03:00
|
|
|
sync_hub: SyncHub | None = self.settings.get("bot", {}).get("sync_hub")
|
|
|
|
|
|
|
|
if not sync_hub:
|
|
|
|
logger.warning("Adding sync hub settings")
|
|
|
|
self.settings["bot"]["sync_hub"] = {
|
|
|
|
"enabled": True,
|
|
|
|
"url": "ws://goober.frii.site"
|
|
|
|
}
|
|
|
|
|
2025-07-26 00:10:31 +03:00
|
|
|
self.commit()
|
|
|
|
|
2025-07-23 15:42:13 +03:00
|
|
|
def reload_settings(self) -> None:
|
|
|
|
with open(self.path, "r") as f:
|
|
|
|
self.__kv_store: dict = json.load(f)
|
|
|
|
|
|
|
|
self.settings = SettingsType(self.__kv_store) # type: ignore
|
|
|
|
self.original_settings = copy.deepcopy(self.settings)
|
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
def commit(self) -> None:
|
|
|
|
with open(self.path, "w") as f:
|
2025-07-23 15:42:13 +03:00
|
|
|
json.dump(self.settings, f, ensure_ascii=False, indent=4)
|
2025-07-22 19:32:19 +03:00
|
|
|
|
|
|
|
self.original_settings = self.settings
|
2025-07-23 10:19:08 +03:00
|
|
|
|
2025-07-22 19:32:19 +03:00
|
|
|
def discard(self) -> None:
|
2025-07-23 10:19:08 +03:00
|
|
|
self.settings = self.original_settings
|
2025-07-23 15:42:13 +03:00
|
|
|
|
2025-07-25 23:17:45 +03:00
|
|
|
def get_plugin_settings(
|
|
|
|
self, plugin_name: str, default: Mapping[Any, Any]
|
|
|
|
) -> Mapping[Any, Any]:
|
|
|
|
return self.settings["cog_settings"].get(plugin_name, default)
|
|
|
|
|
|
|
|
def set_plugin_setting(
|
|
|
|
self, plugin_name: str, new_settings: Mapping[Any, Any]
|
|
|
|
) -> None:
|
|
|
|
"""Changes a plugin setting. Commits changes"""
|
|
|
|
self.settings["cog_settings"][plugin_name] = new_settings
|
|
|
|
|
|
|
|
self.commit()
|
|
|
|
|
2025-07-23 15:42:13 +03:00
|
|
|
def add_admin_log_event(self, event: AdminLogEvent):
|
|
|
|
if not os.path.exists(self.log_path):
|
|
|
|
logger.warning("Admin log doesn't exist!")
|
|
|
|
with open(self.log_path, "w") as f:
|
|
|
|
json.dump([], f)
|
|
|
|
|
|
|
|
with open(self.log_path, "r") as f:
|
|
|
|
logs: List[AdminLogEvent] = json.load(f)
|
|
|
|
|
|
|
|
logs.append(event)
|
|
|
|
|
|
|
|
with open(self.log_path, "w") as f:
|
|
|
|
json.dump(logs, f, ensure_ascii=False, indent=4)
|
|
|
|
|
|
|
|
|
|
|
|
instance: Settings = Settings()
|