transitous rewrite: refactor config

This commit is contained in:
Kaaninchen
2026-08-16 21:09:28 +02:00
parent 41e185a211
commit 8e9fa7c2f2
7 changed files with 111 additions and 41 deletions
+25 -12
View File
@@ -1,20 +1,33 @@
{ {
"discord": {
"token": "", "token": "",
"stations": ["Hamburg Hbf", "München Hbf", "Köln Hbf", "Amsterdam Centraal"],
"dbf": "https://dbf.finalrewind.org",
"server": , "server": ,
"vc": , "vc": ,
"random": true,
"emojis": true,
"formatting": "┇", "formatting": "┇",
"announcements": true, "emojis": true
"voice_announcements: [ },
{ "connections": {
"enabled": false, "stations": [
"stations": { ""
"general": "" ],
} "blacklist": [],
"min_duration": 5,
"max_duration": null,
"max_wait_time": 6,
"timezone": "Europe/Berlin"
},
"announcements": {
"enabled": true,
"voice": [
{
"enabled": false,
"stations": {
"general": "general.aac",
} }
}
] ]
"blacklist": [] },
"http": {
"user_agent": "Gleiswechsel-Discord-Bot"
}
} }
+5 -5
View File
@@ -1,5 +1,6 @@
import discord import discord
from src.utils import config, logger from src.utils import logger
from src.config import config
from src.dc.handlers import rename_vc from src.dc.handlers import rename_vc
from src.dc.helpers import validate_channel from src.dc.helpers import validate_channel
from src.dc.commands import setup_commands from src.dc.commands import setup_commands
@@ -16,22 +17,21 @@ async def on_ready():
if not _bot_initialized: if not _bot_initialized:
_bot_initialized = True _bot_initialized = True
server_id = config["server"] server_id = config.discord.server
server_vc_id = config["vc"] server_vc_id = config.discord.vc
channel = validate_channel(bot=bot, server_id=server_id, channel_id=server_vc_id) channel = validate_channel(bot=bot, server_id=server_id, channel_id=server_vc_id)
await rename_vc(bot, voice_channel=channel) await rename_vc(bot, voice_channel=channel)
else: else:
logger("Reconnected to discord gateway, this wont disturb your current ride") logger("Reconnected to discord gateway, this wont disturb your current ride")
try: try:
bot.run(config["token"]) bot.run(config.discord.token)
except: except:
logger("Feher peim parsen des tokens", "fatal") logger("Feher peim parsen des tokens", "fatal")
''' '''
TODO TODO
- discord status - discord status
- config cleanup
- multi language support - multi language support
- README - README
''' '''
+5 -4
View File
@@ -3,11 +3,12 @@ import random
import json import json
from datetime import datetime, timezone from datetime import datetime, timezone
from src.utils import logger, config, get_train_name, convert_iso_string, validate_connection from src.utils import logger, get_train_name, convert_iso_string, validate_connection
from src.config import config
stations = config["stations"] stations = config.connections.stations
blacklist = config["blacklist"] blacklist = config.connections.blacklist
user_agent = config["http"]["user_agent"] user_agent = config.http.user_agent
headers = { headers = {
"User-Agent": f"{user_agent}" "User-Agent": f"{user_agent}"
+58
View File
@@ -0,0 +1,58 @@
import json
import os
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class DiscordConfig:
token: str
server: int
vc: int
formatting: str
emojis: bool
@dataclass
class ConnectionsConfig:
stations: list[str]
blacklist: list[str]
min_duration: int
max_wait_time: int
timezone: str
max_duration: Optional[int] = None
@dataclass
class VoiceAnnouncementConfig:
enabled: bool
stations: dict[str, str]
@dataclass
class AnnouncementConfig:
enabled: bool
voice: list[VoiceAnnouncementConfig]
@dataclass
class HttpConfig:
user_agent: str
@dataclass
class Config:
discord: DiscordConfig
connections: ConnectionsConfig
announcements: AnnouncementConfig
http: HttpConfig
def _load_config() -> Config:
with open("config.json", "r") as file:
raw = json.load(file)
return Config(
discord=DiscordConfig(**raw["discord"]),
connections=ConnectionsConfig(**raw["connections"]),
announcements=AnnouncementConfig(
enabled=raw["announcements"]["enabled"],
voice=[VoiceAnnouncementConfig(**v) for v in raw["announcements"]["voice"]],
),
http=HttpConfig(**raw["http"]),
)
config = _load_config()
+4 -4
View File
@@ -3,7 +3,8 @@ import asyncio
import random import random
from datetime import datetime, timedelta, date from datetime import datetime, timedelta, date
from src.utils import logger, channel_formatting, choose_connection, config, get_sound_path from src.utils import logger, channel_formatting, choose_connection, get_sound_path
from src.config import config
_scheduled_task: asyncio.Task | None = None _scheduled_task: asyncio.Task | None = None
@@ -62,7 +63,6 @@ async def _schedule_next_transfer(bot: discord.Bot, arrival, voice_channel: disc
if wait_seconds > announcement_countdown: if wait_seconds > announcement_countdown:
wait_until_end_announcement = wait_seconds - announcement_countdown wait_until_end_announcement = wait_seconds - announcement_countdown
await asyncio.sleep(wait_until_end_announcement) await asyncio.sleep(wait_until_end_announcement)
await asyncio.sleep(5)
await announcer("ende", voice_channel, destination) await announcer("ende", voice_channel, destination)
await asyncio.sleep(announcement_countdown) await asyncio.sleep(announcement_countdown)
else: else:
@@ -74,8 +74,8 @@ async def _schedule_next_transfer(bot: discord.Bot, arrival, voice_channel: disc
async def announcer(announcement: str, voice_channel: discord.VoiceChannel, destination = None): async def announcer(announcement: str, voice_channel: discord.VoiceChannel, destination = None):
from src.dc.embeds import build_info_embed, build_announcement_embed from src.dc.embeds import build_info_embed, build_announcement_embed
announcements_enabled = config.get("announcements", True) announcements_enabled = config.announcements.enabled
voice_announcement_enabled = config["voice_announcements"][0]["enabled"] voice_announcement_enabled = config.announcements.voice[0].enabled
if announcements_enabled: if announcements_enabled:
if len(voice_channel.members) > 0: if len(voice_channel.members) > 0:
+2 -1
View File
@@ -4,11 +4,12 @@ from src.utils import logger
def validate_channel(bot: discord.bot, server_id: int, channel_id: int): def validate_channel(bot: discord.bot, server_id: int, channel_id: int):
guild = bot.get_guild(server_id) guild = bot.get_guild(server_id)
channel = guild.get_channel(channel_id)
if guild is None: if guild is None:
logger(f"Es konnte kein Server mit der ID {server_id} gefunden werden", "fatal") logger(f"Es konnte kein Server mit der ID {server_id} gefunden werden", "fatal")
return False
channel = guild.get_channel(channel_id)
if not isinstance(channel, discord.VoiceChannel): if not isinstance(channel, discord.VoiceChannel):
logger(f"Es konnte kein VC mit der id {channel_id} gefunden werden", "fatal") logger(f"Es konnte kein VC mit der id {channel_id} gefunden werden", "fatal")
return False return False
+11 -14
View File
@@ -1,9 +1,9 @@
import json
import os import os
import importlib import importlib
import random import random
from pathlib import Path from pathlib import Path
from datetime import datetime, timedelta, timezone, date from datetime import datetime, timedelta, timezone
from src.config import config
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
import src.data.operators as operators import src.data.operators as operators
@@ -11,8 +11,6 @@ from src.data.emojis import emoji_list
_operator_mtime = None _operator_mtime = None
with open("config.json", "r") as file:
config = json.load(file)
def logger(msg, log_type="info") -> str: def logger(msg, log_type="info") -> str:
status = log_type.upper() status = log_type.upper()
@@ -37,7 +35,7 @@ def validate_connection(start_time: str, end_time: str, station_departure: str)
logger(f"Verbindung liegt bereits in der Vergangenheit: {start_dt}", "error") logger(f"Verbindung liegt bereits in der Vergangenheit: {start_dt}", "error")
return False return False
max_wait_time = config.get("max_wait_time", 6) max_wait_time = config.connections.max_wait_time
start_dt = datetime.fromisoformat(start_time.replace("Z", "+00:00")) start_dt = datetime.fromisoformat(start_time.replace("Z", "+00:00"))
if start_dt > now + timedelta(hours=max_wait_time): if start_dt > now + timedelta(hours=max_wait_time):
logger(f"Verbindung liegt zu weit in der Zukunft: {start_dt}", "error") logger(f"Verbindung liegt zu weit in der Zukunft: {start_dt}", "error")
@@ -47,13 +45,13 @@ def validate_connection(start_time: str, end_time: str, station_departure: str)
trip_duration = (end_dt - station_departure_dt).total_seconds() trip_duration = (end_dt - station_departure_dt).total_seconds()
trip_duration_minutes = str(timedelta(seconds=trip_duration)) trip_duration_minutes = str(timedelta(seconds=trip_duration))
min_duration = config.get("min_duration", 10) min_duration = config.connections.min_duration
min_duration_seconds = min_duration * 60 min_duration_seconds = min_duration * 60
if trip_duration < min_duration_seconds: if trip_duration < min_duration_seconds:
logger(f"Verbindung ist mit {trip_duration_minutes} zu kurz (mindestens {min_duration} Minuten gewollt)", "error") logger(f"Verbindung ist mit {trip_duration_minutes} zu kurz (mindestens {min_duration} Minuten gewollt)", "error")
return False return False
max_duration = config.get("max_duration", "") max_duration = config.connections.max_duration
if max_duration: if max_duration:
max_duration_seconds = max_duration * 60 max_duration_seconds = max_duration * 60
if max_duration_seconds < trip_duration: if max_duration_seconds < trip_duration:
@@ -63,7 +61,7 @@ def validate_connection(start_time: str, end_time: str, station_departure: str)
return True return True
def convert_iso_string(isostring) -> str: def convert_iso_string(isostring) -> str:
timezone = config.get("timezone", "Europe/Berlin") timezone = config.connections.timezone
dt = datetime.fromisoformat(isostring.replace('Z', '+00:00')) dt = datetime.fromisoformat(isostring.replace('Z', '+00:00'))
dt = dt.astimezone(ZoneInfo(timezone)) dt = dt.astimezone(ZoneInfo(timezone))
@@ -72,9 +70,9 @@ def convert_iso_string(isostring) -> str:
return dt.strftime('%H:%M') return dt.strftime('%H:%M')
def channel_formatting(mode: str) -> str: def channel_formatting(mode: str) -> str:
formatting = config.get("formatting", "") formatting = config.discord.formatting
if config.get("emojis", True): if config.discord.formatting:
emoji = emoji_list.get(mode) emoji = emoji_list.get(mode)
if emoji is None: if emoji is None:
emoji = emoji_list.get("Fallback") emoji = emoji_list.get("Fallback")
@@ -134,14 +132,13 @@ def get_operator_metadata(agency: str, route_color: str) -> dict:
} }
def get_sound_path(destination) -> str | None: def get_sound_path(destination) -> str | None:
voice_announcement_config = config["voice_announcements"][0] voice_stations = config.announcements.voice[0].stations
voice_stations = voice_announcement_config["stations"]
if destination in voice_stations: if destination in voice_stations:
announcement_for = destination announcement_for = destination
else: else:
general_config = voice_stations.get("general", "") general_sound_enabled = voice_stations.get("general", "")
if not general_config: if not general_sound_enabled:
return None return None
announcement_for = "general" announcement_for = "general"