transitous rewrite: announcements

This commit is contained in:
Kaaninchen
2026-08-16 17:22:50 +02:00
parent a75b12ea31
commit c563062b9a
5 changed files with 107 additions and 8 deletions
-1
View File
@@ -34,7 +34,6 @@ TODO
- discord status - discord status
- text announcements - text announcements
- voice announcements - voice announcements
- improved error handling (retry connection)
- multi language support - multi language support
- README - README
''' '''
+19
View File
@@ -56,3 +56,22 @@ def build_info_embed() -> discord.Embed:
embed.set_thumbnail(url=metadata["logo"]) embed.set_thumbnail(url=metadata["logo"])
return embed return embed
def build_announcement_embed(msg):
from src.dc.handlers import trip
agency = trip["agency"]
metadata = get_operator_metadata(agency, trip["route_color"])
embed = discord.Embed(
title = "Informationen zu ihrer Fahrt",
description=msg,
color=metadata["color"]
)
embed.set_author(name=agency)
embed.set_thumbnail(url=metadata["logo"])
footer = build_embed_footer(trip["mode"], metadata.get("slogan"))
embed.set_footer(text=footer["text"], icon_url=footer["icon"])
return embed
+59 -4
View File
@@ -1,8 +1,9 @@
import discord import discord
import asyncio import asyncio
import random
from datetime import datetime, timedelta, date from datetime import datetime, timedelta, date
from src.utils import logger, channel_formatting, choose_connection from src.utils import logger, channel_formatting, choose_connection, config, get_sound_path
_scheduled_task: asyncio.Task | None = None _scheduled_task: asyncio.Task | None = None
@@ -38,9 +39,12 @@ async def rename_vc(bot: discord.Bot, voice_channel, from_scheduler: bool = Fals
logger(f"Name geändert!") logger(f"Name geändert!")
_scheduled_task = asyncio.create_task(_schedule_next_transfer(bot, arrival, voice_channel)) await announcer(bot, "umstieg", voice_channel)
async def _schedule_next_transfer(bot, arrival, voice_channel): _scheduled_task = asyncio.create_task(_schedule_next_transfer(bot, arrival, voice_channel, trip["to"]))
async def _schedule_next_transfer(bot: discord.Bot, arrival, voice_channel: discord.VoiceChannel, destination: str):
now = datetime.now() now = datetime.now()
parsed_time = datetime.strptime(arrival, "%H:%M").time() parsed_time = datetime.strptime(arrival, "%H:%M").time()
arrival_dt = datetime.combine(date.today(), parsed_time) arrival_dt = datetime.combine(date.today(), parsed_time)
@@ -49,12 +53,63 @@ async def _schedule_next_transfer(bot, arrival, voice_channel):
arrival_dt += timedelta(days=1) arrival_dt += timedelta(days=1)
wait_seconds = (arrival_dt - now).total_seconds() wait_seconds = (arrival_dt - now).total_seconds()
# announcement_countdown = random.randrange(180, 300)
announcement_countdown = 3
if wait_seconds > 0: if wait_seconds > 0:
remaining = str(timedelta(seconds=wait_seconds)) remaining = str(timedelta(seconds=wait_seconds))
logger(f"Nächster Umstieg in {remaining.split('.')[0]} ({arrival} Uhr)") logger(f"Nächster Umstieg in {remaining.split('.')[0]} ({arrival} Uhr)")
await asyncio.sleep(wait_seconds) if wait_seconds > announcement_countdown:
wait_until_end_announcement = wait_seconds - announcement_countdown
# await asyncio.sleep(wait_until_end_announcement)
await asyncio.sleep(5)
await announcer(bot, "ende", voice_channel, destination)
await asyncio.sleep(announcement_countdown)
else:
await asyncio.sleep(wait_seconds)
logger("Zug angekommen, wähle neue Verbindung") logger("Zug angekommen, wähle neue Verbindung")
await rename_vc(bot, voice_channel, from_scheduler=True) await rename_vc(bot, voice_channel, from_scheduler=True)
async def announcer(bot: discord.Bot, announcement: str, voice_channel: discord.VoiceChannel, destination = None):
from src.dc.embeds import build_info_embed, build_announcement_embed
announcements_enabled = config.get("announcements", True)
voice_announcement_enabled = config["voice_announcements"][0]["enabled"]
if announcements_enabled:
if len(voice_channel.members) > 0:
match announcement:
case "ende":
embed = build_announcement_embed(
f'Sehr geehrte Fahrgäste,\nIn wenigen Minuten erreichen wir {destination}. Dieser Zug endet dort.\n\nWir wünschen Ihnen eine angenehme Weiterreise.\n\nVielen Dank für ihr Vertrauen und auf Wiedersehen.')
if voice_announcement_enabled:
await voice_announcer(bot, destination, voice_channel)
case "umstieg":
embed = build_info_embed()
case _:
logger(f"Unbekanntes Announcements: {announcement}")
embed = None
if embed:
await voice_channel.send(embed=embed)
else:
logger(f"Announcement {announcement} wird geskipped, keiner da")
return
async def voice_announcer(bot: discord.bot, destination: str, voice_channel: discord.VoiceChannel):
sound_path = get_sound_path(destination=destination)
if sound_path is None:
return
logger(f"VC wird betreten, spiele {sound_path}")
vc = await voice_channel.connect(timeout=15, reconnect=True)
audio_source = discord.FFmpegPCMAudio(sound_path)
if not vc.is_playing():
def after_playing(error):
if error:
logger(f"Player error: {error}", "error")
bot.loop.create_task(vc.disconnect())
logger("VC wird verlassen")
vc.play(audio_source, after=after_playing)
+1 -1
View File
@@ -1,6 +1,6 @@
import discord import discord
from datetime import datetime, timedelta from datetime import datetime, timedelta
from src.utils import logger, convert_iso_string 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)
+26
View File
@@ -1,6 +1,8 @@
import json import json
import os import os
import importlib import importlib
import random
from pathlib import Path
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
@@ -130,3 +132,27 @@ def get_operator_metadata(agency: str, route_color: str) -> dict:
"color": color, "color": color,
"slogans": slogans "slogans": slogans
} }
def get_sound_path(destination) -> str | None:
voice_announcement_config = config["voice_announcements"][0]
voice_stations = voice_announcement_config["stations"]
if destination in voice_stations:
announcement_for = destination
else:
general_config = voice_stations.get("general", "")
if general_config == "":
return None
announcement_for = "general"
if voice_stations.values() == list:
sound_file = random.choice(voice_stations.get(announcement_for))
else:
sound_file = voice_stations.get(announcement_for)
sound_path = f"src/data/announcements/{sound_file}"
if Path(sound_path).is_file() is False:
logger(f"Konnte Datei {sound_path} nicht finden", "error")
return None
return sound_path