transitous rewrite: make sure to only use connections in the future

This commit is contained in:
Kaaninchen
2026-08-16 10:43:38 +02:00
parent 53358c08b1
commit f3d9a25f95
5 changed files with 93 additions and 48 deletions
+13 -6
View File
@@ -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
- 1024 embed limit
- Automatic transfer
- discord status
- text announcements
- voice announcements
- improved error handling (retry connection)
- multi language support
- random = False
'''
+37 -26
View File
@@ -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
@@ -35,55 +36,65 @@ 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(f"{endpoint}/api/v5/stoptimes", params=params, headers=headers)
response.raise_for_status()
data = response.json()
except requests.RequestException as e:
print(e)
break
try:
response = requests.get(req, headers=headers)
response.raise_for_status()
data = response.json()
except requests.RequestException as e:
print(e)
return None
stop_times = data.get("stopTimes", [])
all_stop_times.extend(stop_times)
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)
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) >= 5:
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}"
+1 -1
View File
@@ -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"]
+25 -9
View File
@@ -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)
+12 -1
View File
@@ -1,11 +1,11 @@
import json
import os
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
import src.data.operators as operators
from src.data.emojis import emoji_list
with open("config.json", "r") as file:
config = json.load(file)
@@ -16,8 +16,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)