mirror of
https://github.com/kaaninchen/Gleiswechsel.git
synced 2026-07-21 19:52:47 +00:00
Compare commits
11
Commits
5d651640ec
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb11a5a85f | ||
|
|
4c032a7f0f | ||
|
|
bf48cd984b | ||
|
|
d3e6b8ac6c | ||
|
|
e0dfc1bada | ||
|
|
7e4c0ee14a | ||
|
|
e289cdb7cf | ||
|
|
463a6d283b | ||
|
|
585bee7a63 | ||
|
|
e86d2f6a6a | ||
|
|
068eaa7b85 |
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 |
@@ -3,43 +3,108 @@ Gleiswechel ist ein Discord Bot, welcher einen Sprachkanal zu einer real-existie
|
||||
|
||||

|
||||
|
||||
Der Bot stellt außerdem den `/info` Befehl dar, welche einem weitere Informationen zur Verbindung zurückgibt
|
||||
Der Bot stellt außerdem den `/info` Befehl dar, welcher einem weitere Informationen zur Verbindung zurückgibt
|
||||
|
||||

|
||||
|
||||
## Setup
|
||||
```sh
|
||||
git clone https://github.com/kaaninchen/Gleiswechsel.git
|
||||
|
||||
# Mit Python
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Mit uv
|
||||
uv venv venv
|
||||
source venv/bin/activate
|
||||
uv pip install -r requirements.txt
|
||||
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
`$ mv config.json.example`
|
||||
```
|
||||
`$ cp config.json.example config.json`
|
||||
```jsonc
|
||||
{
|
||||
"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
|
||||
"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.
|
||||
"dbf": "https://dbf.finalrewind.org", // Die DBF Instanz. Normalerweise müsste man hier nichts ändern
|
||||
"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)
|
||||
"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)
|
||||
"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.
|
||||
<details>
|
||||
<summary>weitere Config Erklärungen</summary>
|
||||
|
||||
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.
|
||||
#### dbf:
|
||||
Falls, aus irgendwelchem Gründen, man nicht die [offizielle DBF Instanz](https://dbf.finalrewind.org) nutzen möchte, hat man die Möglichkeiten seine eigene zu hosten. Instruction dazu gibts auf dem [zuständigen Repo](https://github.com/derf/db-fakedisplay). Dafür kann man das Feld in der config mit der eigenen URL austauschen.
|
||||
|
||||
## Metadaten
|
||||
#### random:
|
||||
Bei kleineren Bahnhöfen stehen an den Anzeigetafeln öfters die Züge lange vor Abfahrt da, weil sonst der Bahnhof leer steht. 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 wäre welcher 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 vergeblich den selben unvollständigen Zug probieren.
|
||||
|
||||
#### 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
|
||||
{
|
||||
"blacklist": [
|
||||
"ICE",
|
||||
"NJ",
|
||||
"ES"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Die Namen der einzelnen Zugtypen kann im Footer von `/info` oder im Terminal log erfahren.
|
||||
|
||||
#### src/data
|
||||
Es kann vorkommen, dass während dem `/info` Befehl das Logo und die Farbe des Bahnuntermehns fehlt.
|
||||
|
||||

|
||||
|
||||
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 [src/data/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 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 eingesetzt. Sollte man einen Zugtypen hinzufügen wollen oder die Emojis ändern/deaktivieren wollen ist dies in [src/data/emojis.py](src/data/emojis.py) möglich. Die Namen der einzelnen Zugtypen kann im Footer von `/info` oder im Terminal log erfahren.
|
||||
|
||||
Den Status, den sich der Bot alle 5 Minuten random auswählt, kann man in [src/data/status.py](src/data/status.py) anpassen.
|
||||
|
||||
</details>
|
||||
|
||||
### Running
|
||||
|
||||
```sh
|
||||
# Python
|
||||
python main.py
|
||||
# ODER
|
||||
python3 main.py
|
||||
|
||||
# uv
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
## Bekannte Bugs
|
||||
#### Stuttgart in Berlin
|
||||
Ich weiß nicht ganz wieso, aber die API vertauscht manchmal die S-Bahn von Berlin mit der S-Bahn von Stuttgart. Es scheint eher ein Upstream-Issue zu sein, weswegen ich da leider mit dem Bot nicht viel ändern kann.
|
||||
Der Bug führt dazu, dass bei manchen S-Bahn Verbindungen `DB Regio AG S-Bahn Stuttgart` als Betreiber der Berlin S-Bahn angezeigt wird. Außerdem gibt die API dem Bot die Ankunftszeiten einer S-Bahn Verbindung von Stuttgart wieder, während die Route von der aus Berlin stammt (Die Route und die Ankunftszeiten werden von zwei verschiedenen Endpoints gepulled: Route: `{dbf}/Berlin%20Hbf.json`, Ankunftszeit: `{dbf}/z/S%20{ID}/Berlin Hbf.json`).
|
||||
Falls das einem zu sehr stört kann man S-Bahns auf die Blacklist packen.
|
||||
|
||||
```json
|
||||
{
|
||||
"blacklist": [
|
||||
"S "
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Allgemein scheint der Berlin HBF eine sehr komische Station zu sein. Die meisten Bugs beim Testing kommt von dieser. Falls jemand mehr weiß sind PR's wie immer willkommen
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"token": "",
|
||||
"stations": [ "Berlin Hbf", "Hamburg Hbf", "München Hbf", "Amsterdam Centraal"],
|
||||
"dbf": "https://dbf.finalrewind.org",
|
||||
"server": ,
|
||||
"vc": ,
|
||||
"formatting": "🚅┇",
|
||||
"random": false
|
||||
"blacklist": [
|
||||
|
||||
]
|
||||
"random": true,
|
||||
"emojis": true,
|
||||
"formatting": "┇",
|
||||
"blacklist": []
|
||||
}
|
||||
@@ -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():
|
||||
@@ -21,13 +21,13 @@ async def on_ready():
|
||||
if not change_status.is_running():
|
||||
change_status.start()
|
||||
await rename_vc(bot)
|
||||
|
||||
'''
|
||||
@bot.event
|
||||
async def on_application_command_error(ctx, error):
|
||||
embed = build_error_embed(f"Ein Fehler ist aufgetreten: {error}")
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
'''
|
||||
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")
|
||||
@@ -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"],
|
||||
}
|
||||
@@ -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
@@ -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",
|
||||
]
|
||||
+6
-3
@@ -2,6 +2,7 @@ import random
|
||||
import discord
|
||||
from datetime import datetime, timedelta
|
||||
import src.handlers as handlers
|
||||
from src.config import config
|
||||
from src.utils import operator_metadata, format_via_list, resolve_operator, logger
|
||||
|
||||
def format_timestamp(timestr):
|
||||
@@ -62,13 +63,15 @@ 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)} • 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")
|
||||
embed.set_footer(text=footer_text, icon_url=f"{dbf}/static/icons/icon-96x96.png")
|
||||
return embed
|
||||
|
||||
def build_error_embed(errormsg) -> discord.Embed:
|
||||
|
||||
+6
-4
@@ -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!")
|
||||
|
||||
|
||||
+16
-3
@@ -5,8 +5,10 @@ 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
|
||||
dbf = config.get("dbf", "https://dbf.finalrewind.org")
|
||||
|
||||
def _reload_operators_if_changed():
|
||||
global _operators_mtime
|
||||
@@ -27,10 +29,10 @@ def random_connection():
|
||||
available_stations = config["stations"].copy()
|
||||
while True:
|
||||
if not available_stations:
|
||||
logger("Keine validen Bahnhöfe. Schlag den richtigen Bahnhofsnamen auf https://dbf.finalrewind.org/ nach", "fatal")
|
||||
logger("Keine validen Bahnhöfe. Schlag den richtigen Bahnhofsnamen auf {dbf} nach", "fatal")
|
||||
|
||||
station = random.choice(available_stations)
|
||||
url = f"https://dbf.finalrewind.org/{station}.json"
|
||||
url = f"{dbf}/{station}.json"
|
||||
blacklist = config.get("blacklist", [])
|
||||
|
||||
try:
|
||||
@@ -71,7 +73,7 @@ def random_connection():
|
||||
}
|
||||
|
||||
def get_train_info(station, train_ID, train_type):
|
||||
url = f"https://dbf.finalrewind.org/z/{train_type}%20{train_ID}/{station}.json"
|
||||
url = f"{dbf}/z/{train_type}%20{train_ID}/{station}.json"
|
||||
logger(f"Fetche {url}")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
@@ -128,6 +130,17 @@ 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 = ""
|
||||
|
||||
if config.get("emojis", True):
|
||||
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')
|
||||
|
||||
Reference in New Issue
Block a user