mirror of
https://github.com/kaaninchen/Gleiswechsel.git
synced 2026-09-17 16:52:47 +00:00
Compare commits
2
Commits
53358c08b1
...
1892c734cd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1892c734cd | ||
|
|
f3d9a25f95 |
@@ -6,15 +6,22 @@ from src.dc.commands import setup_commands
|
||||
|
||||
bot = discord.Bot(intents=discord.Intents.all())
|
||||
setup_commands(bot=bot)
|
||||
_bot_initialized = False
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
server_id = config["server"]
|
||||
server_vc_id = config["vc"]
|
||||
channel = validate_channel(bot=bot, server_id=server_id, channel_id=server_vc_id)
|
||||
global _bot_initialized
|
||||
|
||||
logger(f"{bot.user} ist online")
|
||||
await rename_vc(bot=bot, voice_channel=channel)
|
||||
|
||||
if not _bot_initialized:
|
||||
_bot_initialized = True
|
||||
server_id = config["server"]
|
||||
server_vc_id = config["vc"]
|
||||
channel = validate_channel(bot=bot, server_id=server_id, channel_id=server_vc_id)
|
||||
await rename_vc(bot, voice_channel=channel)
|
||||
else:
|
||||
logger("Reconnected to discord gateway, this wont disturb your current ride")
|
||||
|
||||
try:
|
||||
bot.run(config["token"])
|
||||
@@ -23,12 +30,12 @@ except:
|
||||
|
||||
'''
|
||||
TODO
|
||||
- Only choose connections in the future
|
||||
- discord reconnection handling
|
||||
- Automatic transfer
|
||||
- 1024 embed limit
|
||||
- automatic reload of operators
|
||||
- discord status
|
||||
- text announcements
|
||||
- voice announcements
|
||||
- improved error handling (retry connection)
|
||||
- multi language support
|
||||
- random = False
|
||||
'''
|
||||
+46
-35
@@ -1,6 +1,7 @@
|
||||
import requests
|
||||
import random
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from src.utils import logger, config, get_train_name, convert_iso_string
|
||||
|
||||
@@ -16,10 +17,10 @@ endpoint = "https://api.transitous.org"
|
||||
|
||||
def get_random_stop_id() -> str:
|
||||
assigned_station = random.choice(stations)
|
||||
req = f"{endpoint}/api/v1/geocode?text={assigned_station}"
|
||||
req = f"{endpoint}/api/v1/geocode"
|
||||
|
||||
try:
|
||||
response = requests.get(req, headers=headers)
|
||||
response = requests.get(req, params={"text": assigned_station}, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
except requests.RequestException as e:
|
||||
@@ -35,61 +36,71 @@ def get_random_stop_id() -> str:
|
||||
return entry["id"]
|
||||
|
||||
def get_random_connection(stop_id: str) -> str:
|
||||
max_pages = 5
|
||||
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
print(f"Aktuelle Zeit für Query: {now}")
|
||||
cursor = None
|
||||
count = 20
|
||||
max_pages = 5
|
||||
min_results = 5
|
||||
trip_ids = []
|
||||
all_stop_times = []
|
||||
|
||||
for _ in range(max_pages):
|
||||
params = f"stopId={stop_id}&n={count}"
|
||||
params = {
|
||||
"stopId": stop_id,
|
||||
"n": 20,
|
||||
"time": now,
|
||||
}
|
||||
if cursor:
|
||||
params += f"&pageCursor={cursor}"
|
||||
params["pageCursor"] = cursor
|
||||
|
||||
req = f"{endpoint}/api/v1/stoptimes?{params}"
|
||||
|
||||
try:
|
||||
response = requests.get(req, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
except requests.RequestException as e:
|
||||
print(e)
|
||||
return None
|
||||
|
||||
trip_ids = []
|
||||
stop_times = data.get("stopTimes", [])
|
||||
for entry in stop_times:
|
||||
trip_id = entry["tripId"]
|
||||
if entry["mode"] in blacklist:
|
||||
continue
|
||||
trip_ids.append(trip_id)
|
||||
|
||||
if len(trip_ids) >= 5:
|
||||
try:
|
||||
response = requests.get(f"{endpoint}/api/v5/stoptimes", params=params, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
except requests.RequestException as e:
|
||||
print(e)
|
||||
break
|
||||
|
||||
stop_times = data.get("stopTimes", [])
|
||||
all_stop_times.extend(stop_times)
|
||||
|
||||
for entry in stop_times:
|
||||
dep = entry.get("place", {}).get("departure") or entry.get("place", {}).get("arrival")
|
||||
print(f"{entry.get('mode')}: {convert_iso_string(dep)}")
|
||||
trip_id = entry["tripId"]
|
||||
if entry["mode"] in blacklist:
|
||||
continue
|
||||
trip_ids.append(entry["tripId"])
|
||||
|
||||
if len(trip_ids) >= min_results:
|
||||
break
|
||||
|
||||
cursor = data.get("nextPageCursor")
|
||||
if not cursor:
|
||||
break
|
||||
|
||||
if not trip_ids:
|
||||
if not trip_ids:
|
||||
logger("Couldn't find any connection", "fatal")
|
||||
return None
|
||||
|
||||
|
||||
trip_id = random.choice(trip_ids)
|
||||
for trip in stop_times:
|
||||
if trip.get("tripId") == trip_id:
|
||||
from_station = trip.get("place").get("name")
|
||||
|
||||
from_station = None
|
||||
for entry in all_stop_times:
|
||||
if entry.get("tripId") == trip_id:
|
||||
from_station = entry.get("place", {}).get("name")
|
||||
break
|
||||
|
||||
print(from_station)
|
||||
return {
|
||||
"trip_id": trip_id,
|
||||
"from_station": from_station
|
||||
}
|
||||
}
|
||||
|
||||
def get_trip_details(trip_id: str, from_station: str) -> dict:
|
||||
req = f"{endpoint}/api/v2/trip?tripId={trip_id}"
|
||||
req = f"{endpoint}/api/v2/trip"
|
||||
|
||||
try:
|
||||
response = requests.get(req, headers=headers)
|
||||
response = requests.get(req, params={"tripId": trip_id}, headers=headers)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
except requests.RequestException as e:
|
||||
@@ -108,7 +119,7 @@ def get_trip_details(trip_id: str, from_station: str) -> dict:
|
||||
departure = convert_iso_string(start_time)
|
||||
arrival = convert_iso_string(end_time)
|
||||
train_name = get_train_name(display_name, mode)
|
||||
|
||||
|
||||
trip_details = {
|
||||
"long_name": f"{train_name} nach {goes_to} von {from_station}",
|
||||
"short_name": display_name,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
emoji_list = {
|
||||
"Fallback": "💺",
|
||||
"BUS": "🚎",
|
||||
"COACH": "🚎",
|
||||
"TRAM": "🚈",
|
||||
"REGIONAL_RAIL": "🚊",
|
||||
"HIGHSPEED_RAIL": "🚅",
|
||||
|
||||
@@ -38,7 +38,7 @@ OPERATORS = {
|
||||
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/ODEG-Logo_Neu.svg/960px-ODEG-Logo_Neu.svg.png",
|
||||
"color": 0x00745C
|
||||
},
|
||||
"Nederlandse Spoorwegen": {
|
||||
"NS": {
|
||||
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Logo_NS.svg/960px-Logo_NS.svg.png",
|
||||
"color": 0X00337F,
|
||||
"slogan": ["Goed op weg", "Welkom in de trein van morgen", "Veilig, Vlug, Voordelig", "we haben een serious probleem", "Neuken in de keuken"]
|
||||
@@ -109,10 +109,12 @@ OPERATOR_ALIASES = {
|
||||
"DB Regio AG Bayern": OPERATORS["db_bayern"],
|
||||
"DB Fernverkehr AG": OPERATORS["db_allgemein"],
|
||||
"DB Regio AG NRW": OPERATORS["db_allgemein"],
|
||||
"DB Regio AG Nord": OPERATORS["db_allgemein"],
|
||||
"DB Regio AG Südost": OPERATORS["db_allgemein"],
|
||||
"DB Regio AG Nordost": OPERATORS["db_allgemein"],
|
||||
"DB Regio AG Mitte": OPERATORS["db_allgemein"],
|
||||
"SBB GmbH": OPERATORS["SBB"],
|
||||
"Schweizerische Bundesbahnen SBB": OPERATORS["SBB"],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+25
-9
@@ -1,26 +1,22 @@
|
||||
import discord
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta, date
|
||||
|
||||
from src.api import transitous
|
||||
from src.utils import logger, channel_formatting
|
||||
from src.utils import logger, channel_formatting, choose_connection
|
||||
|
||||
_scheduled_task: asyncio.Task | None = None
|
||||
|
||||
async def rename_vc(bot: discord.Bot, voice_channel, from_scheduler: bool = False):
|
||||
global trip
|
||||
global trip, _scheduled_task
|
||||
if not from_scheduler and _scheduled_task and not _scheduled_task.done():
|
||||
_scheduled_task.cancel()
|
||||
|
||||
station_id = transitous.get_random_stop_id()
|
||||
connection = transitous.get_random_connection(station_id)
|
||||
trip = transitous.get_trip_details(connection["trip_id"], connection["from_station"])
|
||||
|
||||
trip = choose_connection()
|
||||
arrival = trip["arrival"]
|
||||
long_name = trip["long_name"]
|
||||
|
||||
print("-----------------")
|
||||
logger(f"Umstieg: {long_name}, Ankunft: {arrival}")
|
||||
logger(f"Umstieg: {long_name}, Ankunft: {arrival} Uhr")
|
||||
logger(f"Betreiber: {trip["agency"]}, Typ: {trip["mode"]}")
|
||||
logger(f"Versuche Namen zu ändern, wenn nichts passiert bin ich im cooldown... (warte bis zu 10min!)")
|
||||
|
||||
@@ -30,3 +26,23 @@ async def rename_vc(bot: discord.Bot, voice_channel, from_scheduler: bool = Fals
|
||||
|
||||
logger(f"Name geändert!")
|
||||
|
||||
_scheduled_task = asyncio.create_task(_schedule_next_transfer(bot, arrival))
|
||||
|
||||
async def _schedule_next_transfer(bot, arrival):
|
||||
now = datetime.now()
|
||||
parsed_time = datetime.strptime(arrival, "%H:%M").time()
|
||||
arrival_dt = datetime.combine(date.today(), parsed_time)
|
||||
|
||||
if arrival_dt < now:
|
||||
arrival_dt += timedelta(days=1)
|
||||
|
||||
wait_seconds = (arrival_dt - now).total_seconds()
|
||||
if wait_seconds > 0:
|
||||
remaining = str(timedelta(seconds=wait_seconds))
|
||||
logger(f"Nächster Umstieg in {remaining.split('.')[0]} ({arrival} Uhr)")
|
||||
|
||||
await asyncio.sleep(wait_seconds)
|
||||
|
||||
logger("Zug angekommen, wähle neue Verbindung")
|
||||
await rename_vc(bot, from_scheduler=True)
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import json
|
||||
import os
|
||||
import importlib
|
||||
from datetime import datetime, timedelta
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import src.data.operators as operators
|
||||
from src.data.emojis import emoji_list
|
||||
|
||||
_operator_mtime = None
|
||||
|
||||
with open("config.json", "r") as file:
|
||||
config = json.load(file)
|
||||
@@ -16,8 +19,19 @@ def logger(msg, log_type="info") -> str:
|
||||
if status == "FATAL":
|
||||
os._exit(1)
|
||||
|
||||
def choose_connection() -> dict:
|
||||
from src.api import transitous
|
||||
station_id = transitous.get_random_stop_id()
|
||||
connection = transitous.get_random_connection(station_id)
|
||||
trip = transitous.get_trip_details(connection["trip_id"], connection["from_station"])
|
||||
|
||||
return trip
|
||||
|
||||
def convert_iso_string(isostring) -> str:
|
||||
timezone = config.get("timezone", "Europe/Berlin")
|
||||
dt = datetime.fromisoformat(isostring.replace('Z', '+00:00'))
|
||||
dt = dt.astimezone(ZoneInfo(timezone))
|
||||
|
||||
if dt.second >= 30:
|
||||
dt += timedelta(minutes=1)
|
||||
|
||||
@@ -43,7 +57,25 @@ def get_train_name(train_name: str, mode: str) -> str:
|
||||
|
||||
return train
|
||||
|
||||
def _reload_operators_if_changed():
|
||||
global _operator_mtime
|
||||
|
||||
path = operators.__file__
|
||||
current_mtime = os.path.getmtime(path)
|
||||
|
||||
if _operator_mtime is None:
|
||||
_operator_mtime = current_mtime
|
||||
return
|
||||
|
||||
if current_mtime != _operator_mtime:
|
||||
importlib.reload(operators)
|
||||
_operator_mtime = current_mtime
|
||||
logger("operators.py wurde automatisch neu geladen (Änderungen erkannt)")
|
||||
|
||||
|
||||
def get_operator_metadata(agency: str, route_color: str) -> dict:
|
||||
_reload_operators_if_changed()
|
||||
|
||||
op_data = operators.OPERATOR_ALIASES.get(agency) or operators.OPERATORS.get(agency) or operators.OPERATORS["fallback"]
|
||||
|
||||
logo = op_data.get("logo", operators.OPERATORS["fallback"]["logo"])
|
||||
|
||||
Reference in New Issue
Block a user