Compare commits

..
7 Commits
Author SHA1 Message Date
Kaaninchen e0dfc1bada Update README 2026-07-20 22:39:55 +02:00
Kaaninchen 7e4c0ee14a update status 2026-07-20 22:11:07 +02:00
Kaaninchen e289cdb7cf README: .github bilder geupdated 2026-07-20 21:51:26 +02:00
Kaaninchen 463a6d283b operators.py: European Sleeper 2026-07-20 21:31:54 +02:00
Kaaninchen 585bee7a63 leerzeichen zwischen emoji und formattierung entfernt 2026-07-20 21:28:42 +02:00
Kaaninchen e86d2f6a6a TGV zu Emojis hinzugefügt 2026-07-20 21:25:15 +02:00
Kaaninchen 068eaa7b85 Dynamische Emojis je nach Zugart 2026-07-20 21:22:09 +02:00
12 changed files with 81 additions and 27 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 110 KiB

+32 -12
View File
@@ -20,26 +20,46 @@ pip install -r requirements.txt
`$ mv config.json.example`
```
{
"token": "", // Discord Token
"stations": [ "Berlin Hbf", "Hamburg Hbf", "München Hbf", "Amsterdam Centraal"], // Stationen deiner Wahl. Im Zweifel auf https://dbf.finalrewind.org/ Namen raussuchen
"server": , // Discord Server ID
"vc": , // Discord VC ID
"formatting": "🚅┇", // Name des Kanals
"random": false // Random Züge aussuchen (true) oder immer die erste Station der Anzeigetafel (false)
"token": "", # Token des Bots
"stations": [ "Berlin Hbf", "Hamburg Hbf", "München Hbf", "Amsterdam Centraal"], # Bahnhöfe, von denen die Anzeigetafelns gelesen werden. Namen kann man auf https://dbf.finalrewind.org/ nachschlagen.
"server": , # Discord Server ID
"vc": , # Server VC ID
"random": true, # Random Zug aus der Anzeigetafel (true) oder erster Zug, der angezeigt wird (false)
"formatting": "┇", # VC Name. Davor steht der Emoji, danach der Zug
"blacklist": [] # Blacklist für bestimmte Zug-Typen
}
```
#### Erklärung bezüglich random:
Bei kleineren Bahnhöfen stehen an den Anzeigetafeln die Namen Züge öfters Stunden vor Abfahrt, da das Gleis sonst frei ist. Dadurch wird auch der Name des VC sehr lange gleich bleiben. Sollte man random ausmachen, würde immer der erste Zug an der Anzeigetafel genommen werden, welcher auch der erst der am frühesten losfährt. Wenn man aber wenige Bahnhöfen zur Auswahl hat könnte es repetitiv werden, da die Züge ja oft hin und her fahren.
#### random:
Bei kleineren Bahnhöfen stehen an den Anzeigetafeln die Namen Züge öfters Stunden, bevor der Zug eigentlich abfährt, da dort sonst keiner fährt. Dadurch wird auch der Name des VC sehr lange gleich bleiben.
Sollte man `random = false` setzen, würde immer der erste Zug an der Anzeigetafel genommen werden, welcher auch der erst der am frühesten losfährt. Wenn man viele Bahnhöfe hat besteht darin keine Gefahr.
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 vergeblichg den selben Zug probieren.
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 Zug probieren.
## Metadaten
#### blacklist:
Die Blacklist ist dafür gedacht, ganze Zugtypen zu ignorieren. So würde man es beispielsweise bevorzugen, dass der Bot keine ICE's, keine NightJets und keine European Sleepers auswählt, da diese sehr lange Strecken haben und der VC somit lange unverändert bleibt:
```
{
...
"blacklist": [
"ICE",
"NJ",
"ES
]
}
```
Die Namen der einzelnen Zugtypen kann mit im Footer von `/info` oder im Terminal log erfahren.
## Data
Es kann vorkommen, dass während dem `/info` Befehl das Logo und die Farbe des Bahnuntermehns fehlt.
![Beispiel für fehlende Daten](.github/info_fehlende_daten.png)
Die zugehörigen Daten lassen sich innerhalb [operators.py](src/data/operators.py) ergänzen. Der Aufbau dabei sollte selbsterklärend sein, dennoch habe ich eine kleine Beschreibung in die Datei hinzugefügt. Bei Änderungen sind PR's willkommen, ebenso wie Issues falls man das nicht selber ändern will da das ja eigentlich mein Job sein sollte.
Die zugehörigen Daten lassen sich innerhalb [operators.py](src/data/operators.py) ergänzen. Der Aufbau dabei sollte selbsterklärend sein, dennoch habe ich eine kleine Beschreibung in die Datei hinzugefügt. Bei Änderungen sind PR's willkommen.
Die Datei wird leider nie vollständig sein da die verschiedenen Fahrtaufträge in Deutschland sehr fragmentiert sind.
Die Statuseinträge, von welchen der Bot alle 5 Minuten einen aussucht, kann mn in [status.py](src/data/operators.py) anpassen
Emojis für die Formattierung werden dynamisch anhand des Zugtypens gepulled. Dabei wird zwischen Nahverkehr und Fernverkehr unterschieden. Bei einem Zugtyp, welcher zu keiner der Kategorie assigned ist, wird ein Fallback Emoji ist. Sollte man einen Zugtypen hinzufügen wollen oder die Emojis ändern/deaktivieren wollen ist dies in [emojis.py](src/data/emojis.py) möglich. Die Namen der einzelnen Zugtypen kann mit im Footer von `/info` oder im Terminal log erfahren.
Die Statuseinträge, von welchen der Bot alle 5 Minuten einen aussucht, kann mn in [status.py](src/data/status.py) anpassen.
+3 -5
View File
@@ -3,9 +3,7 @@
"stations": [ "Berlin Hbf", "Hamburg Hbf", "München Hbf", "Amsterdam Centraal"],
"server": ,
"vc": ,
"formatting": "🚅┇",
"random": false
"blacklist": [
]
"random": true,
"formatting": "┇",
"blacklist": []
}
+2 -2
View File
@@ -13,7 +13,7 @@ setup_commands(bot)
@tasks.loop(minutes=5)
async def change_status():
status = random.choice(discord_status)
await bot.change_presence(activity=discord.Game(name=status))
await bot.change_presence(activity=discord.Game(name=f"{status} • /info"))
@bot.event
async def on_ready():
@@ -30,4 +30,4 @@ async def on_application_command_error(ctx, error):
try:
bot.run(config['token'])
except:
print("An error occured while parsing the token (check the config!)", "fatal")
print("Fehler beim parsen des token", "fatal")
+15
View File
@@ -0,0 +1,15 @@
emoji_list = {
"Fallback": "🚉",
"Nahverkehr": "🚃",
"Höchstgeschwindigkeit": "🚄"
}
train_types = { # Unvollständig! Benötigt testing
"ICE": emoji_list["Höchstgeschwindigkeit"],
"TGV": emoji_list["Höchstgeschwindigkeit"],
"RE": emoji_list["Nahverkehr"],
"RB": emoji_list["Nahverkehr"],
"ARV": emoji_list["Nahverkehr"],
"BRB": emoji_list["Nahverkehr"],
}
+4
View File
@@ -78,6 +78,10 @@ OPERATORS = {
"Westbahn Management GmbH": {
"logo": "https://corporate.westbahn.at/uploads/Logos/westbahn2025-logo-signet-small.png",
"color": 0x1D4A83
},
"European Sleeper": {
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/European_Sleeper_Logo.svg/960px-European_Sleeper_Logo.svg.png",
"color": 0xEB4A27
}
}
+7 -2
View File
@@ -5,7 +5,12 @@ discord_status = [
"Störung an der Weiche",
"Heute ohne Bordbistro",
"SEV ist eingerichtet",
"BahnBonus Status",
"Gleiswechsel!",
"Zug entgleist :("
"Zug entgleist :(",
"Die Bundespolizei ist informiert",
"Dieser Zug endet hier",
"Außerplanmäßiger Halt in Oberhausen Hbf",
"Verspätung aus vorheriger Fahrt",
"Der Zug hat keine Bremsen",
"Heute ohne Klimatisierung",
]
+3 -2
View File
@@ -62,10 +62,11 @@ def build_info_embed() -> discord.Embed | None:
embed.add_field(name="Route", value="\n".join(route_lines))
slogans = operator_infos.get("slogan")
footer_notice = f"Daten großzügig bereitgestellt von dbf.finalrewind.org • Typ: {handlers.train_type}"
footer_text = (
f"{random.choice(slogans)}Daten großzügig bereitgestellt von dbf.finalrewind.org"
f"{random.choice(slogans)}{footer_notice}"
if slogans else
"Daten großzügig bereitgestellt von dbf.finalrewind.org"
footer_notice
)
embed.set_footer(text=footer_text, icon_url="https://dbf.finalrewind.org/static/icons/icon-96x96.png")
+6 -4
View File
@@ -2,13 +2,13 @@ import discord
from datetime import datetime, timedelta
import asyncio
from src.config import config
from src.utils import random_connection, get_train_info, logger
from src.utils import random_connection, get_train_info, get_channel_formatting, logger
current = None
_scheduled_task: asyncio.Task | None = None
async def rename_vc(bot: discord.Bot):
global current, train_name, train_info, _scheduled_task
global current, train_name, train_info, train_type, _scheduled_task
guild = bot.get_guild(int(config["server"]))
if guild is None:
@@ -51,14 +51,16 @@ async def rename_vc(bot: discord.Bot):
train_name = f"{train} nach {current['destination']} von {current['station']}"
logger(f"Vorbereitung auf {train_name} (typ: {train_type})")
arrival = datetime.fromisoformat((train_info["arrival"]))
formatting = get_channel_formatting(train_type)
_scheduled_task = asyncio.create_task(_schedule_next_umstieg(bot, arrival))
print("-----------------------------------------")
logger(f"Umstieg: {train_name}")
logger(f"Betreiber: {train_info['operators']}")
logger(f"Betreiber: {''.join(train_info['operators'])}")
logger(f"Train-Type: {train_type}")
logger(f"Wenn der Name nicht geändert wird bin ich im Cooldown")
await channel.edit(name=f"{config['formatting']}{train_name}")
await channel.edit(name=f"{formatting}{train_name}")
await channel.set_status(f"Ankunft um {arrival.strftime('%H:%M')}")
logger(f"Name geändert!")
+9
View File
@@ -5,6 +5,7 @@ import importlib
from datetime import datetime
from src.config import config
import src.data.operators as operators_module
import src.data.emojis as emojis
_operators_mtime = None
@@ -128,6 +129,14 @@ def operator_metadata(operator):
return operators_module.OPERATORS.get(operator, operators_module.OPERATORS["fallback"])
def get_channel_formatting(train_type):
formatting = config.get("formatting", "")
train_emoji = emojis.train_types.get(train_type)
if train_emoji is None:
train_emoji = emojis.emoji_list.get("Fallback", "")
return f"{train_emoji}{formatting}"
def logger(msg, log_type="info"):
status = log_type.upper()
current_time = datetime.now().strftime('%X')