From 24edd1fe05d4346eebf4c56900ceb815d95e65cf Mon Sep 17 00:00:00 2001 From: Kaaninchen <124433727+kaaninchen@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:53:07 +0200 Subject: [PATCH] Announcements --- README.md | 8 +++++++- config.json.example | 3 ++- src/embeds.py | 41 +++++++++++++++++++++++++++++++++-------- src/handlers.py | 40 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 80 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1506901..25590a2 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ uv pip install -r requirements.txt "server": , // Discord Server ID "vc": , // Server VC ID "random": true, // Random Zug aus der Anzeigetafel (true) oder erster Zug, der angezeigt wird (false) - "emojis": true, // Emoji Namen beim Channel-Namen (true) oder nicht (false) + "emojis": true, // Emoji Namen beim Channel-Namen (true) oder nicht (false), + "announcemenents": true, // Announcements zur aktuellen Zugreise im VC-Kanal ja (true) oder nein (false) "formatting": "┇", // VC Name. Davor steht der Emoji, danach der Zug. "blacklist": [] // Blacklist für bestimmte Zug-Typen } @@ -53,6 +54,11 @@ Sollte man `random = false` setzen, würde immer der erste Zug an der Anzeigetaf Wenn man nur einen Bahnhof hat ist es stark empfohlen random zu nutzen. Sonst könnte der Bot bei unvollständigen Einträgen in einer Schleife immer wieder vergeblich den selben unvollständigen Zug probieren. +#### announcements: +Der Bot kann während der Zugreise Ankündigungen in den Textkanal vom Sprachkanal schicken. Das würde er aber auch nur machen wenn sich dort mindestens eine Person aufhält. Aktuelle Announcements: +- 3-5 Min vor Umstieg gibt es eine Ankündigung dafür +- Info Embed bei Umstieg + #### blacklist: Die Blacklist ist dafür gedacht, ganze Zugtypen zu ignorieren. Beispielsweise möchte man, dass der Bot keine ICE's, keine NightJets und keine European Sleepers auswählt, da diese sehr lange Strecken fahren und der VC somit lange unverändert bleibt: ```json diff --git a/config.json.example b/config.json.example index 59bcbf4..c4941ca 100644 --- a/config.json.example +++ b/config.json.example @@ -1,11 +1,12 @@ { "token": "", - "stations": [ "Berlin Hbf", "Hamburg Hbf", "München Hbf", "Amsterdam Centraal"], + "stations": ["Hamburg Hbf", "München Hbf", "Köln Hbf", "Amsterdam Centraal"], "dbf": "https://dbf.finalrewind.org", "server": , "vc": , "random": true, "emojis": true, + "announcements": true, "formatting": "┇", "blacklist": [] } \ No newline at end of file diff --git a/src/embeds.py b/src/embeds.py index 5b1a727..2097669 100644 --- a/src/embeds.py +++ b/src/embeds.py @@ -24,6 +24,20 @@ def format_iso_timestamp(isostr): parsed_time = discord.utils.parse_time(isostr) return discord.utils.format_dt(parsed_time, style="t") +def build_embed_footer(operator_slogans): + dbf = config.get("dbf", "https://dbf.finalrewind.org") + footer_notice = f"Daten großzügig bereitgestellt von {dbf} • Typ: {handlers.train_type}" + footer_text = ( + f"{random.choice(operator_slogans)} • {footer_notice}" + if operator_slogans else + footer_notice + ) + icon = f"{dbf}/static/icons/icon-96x96.png" + return { + "text": footer_text, + "icon": icon + } + def build_info_embed() -> discord.Embed | None: conn = handlers.current info = handlers.train_info @@ -62,16 +76,27 @@ def build_info_embed() -> discord.Embed | None: embed.add_field(name="Route", value="\n".join(route_lines)) - slogans = operator_infos.get("slogan") - dbf = config.get("dbf", "https://dbf.finalrewind.org") - footer_notice = f"Daten großzügig bereitgestellt von {dbf} • Typ: {handlers.train_type}" - footer_text = ( - f"{random.choice(slogans)} • {footer_notice}" - if slogans else - footer_notice + footer = build_embed_footer(operator_infos.get("slogan")) + embed.set_footer(text=footer["text"], icon_url=footer["icon"]) + + return embed + +def build_announcement_embed(msg): + current_operator = resolve_operator(handlers.train_info["operators"]) + operator_infos = operator_metadata(current_operator) + + embed = discord.Embed( + title = "Informationen zu Ihrer Fahrt", + description=msg, + color=operator_infos["color"] ) - embed.set_footer(text=footer_text, icon_url=f"{dbf}/static/icons/icon-96x96.png") + embed.set_author(name=current_operator) + embed.set_thumbnail(url=operator_infos["logo"]) + + footer = build_embed_footer(operator_infos.get("slogan")) + embed.set_footer(text=footer["text"], icon_url=footer["icon"]) + return embed def build_error_embed(errormsg) -> discord.Embed: diff --git a/src/handlers.py b/src/handlers.py index 22b4ee9..31c800d 100644 --- a/src/handlers.py +++ b/src/handlers.py @@ -1,12 +1,34 @@ import discord from datetime import datetime, timedelta import asyncio +import random from src.config import config from src.utils import random_connection, get_train_info, get_channel_formatting, logger +from src.embeds import build_announcement_embed, build_info_embed current = None _scheduled_task: asyncio.Task | None = None +async def announcer(bot, announcement): + voice_channel = bot.get_channel(config["vc"]) + if len(voice_channel.members) > 0: + match announcement: + case "ende": + embed = build_announcement_embed( + f'Sehr geehrte Fahrgäste,\nIn wenigen Minuten erreichen wir {current['destination']}. Dieser Zug endet dort.\n\nWir wünschen Ihnen eine angenehme Weiterreise.\n\nVielen Dank für Ihr Vertrauen und auf Wiedersehen.') + case "umstieg": + embed = build_info_embed() + case _: + embed = None + if embed is None: + logger(f"Unbekanntes Announcement: {announcement}") + else: + await voice_channel.send(embed=embed) + else: + logger(f"Announcement {announcement} wird geskipped, keiner da") + return + + async def rename_vc(bot: discord.Bot): global current, train_name, train_info, train_type, _scheduled_task @@ -64,13 +86,27 @@ async def rename_vc(bot: discord.Bot): await channel.set_status(f"Ankunft um {arrival.strftime('%H:%M')}") logger(f"Name geändert!") + if config.get("announcements", True): + await announcer(bot, "umstieg") + return True async def _schedule_next_umstieg(bot, arrival): + announcement = config.get("announcements", True) + announcement_countdown = random.randrange(180, 300) # letzte station announcement ist meistens 3-5min vor ankunft wait_seconds = (arrival - datetime.now()).total_seconds() if wait_seconds > 0: remaining = str(timedelta(seconds=wait_seconds)) - logger(f"Nächster Umstieg in {remaining.split(".")[0]} ({arrival.strftime('%H:%M:%S')} Uhr)") - await asyncio.sleep(wait_seconds) + logger(f"Nächster Umstieg in {remaining.split('.')[0]} ({arrival.strftime('%H:%M:%S')} Uhr)") + + if announcement and wait_seconds > announcement_countdown: + wait_until_end_announcement = wait_seconds - announcement_countdown + await asyncio.sleep(wait_until_end_announcement) + await announcer(bot, "ende") + await asyncio.sleep(announcement_countdown) + + else: + await asyncio.sleep(wait_seconds) + logger("Zug angekommen, wähle neue Verbindung...") await rename_vc(bot) \ No newline at end of file