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())
|
bot = discord.Bot(intents=discord.Intents.all())
|
||||||
setup_commands(bot=bot)
|
setup_commands(bot=bot)
|
||||||
|
_bot_initialized = False
|
||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
|
global _bot_initialized
|
||||||
|
|
||||||
|
logger(f"{bot.user} ist online")
|
||||||
|
|
||||||
|
if not _bot_initialized:
|
||||||
|
_bot_initialized = True
|
||||||
server_id = config["server"]
|
server_id = config["server"]
|
||||||
server_vc_id = config["vc"]
|
server_vc_id = config["vc"]
|
||||||
channel = validate_channel(bot=bot, server_id=server_id, channel_id=server_vc_id)
|
channel = validate_channel(bot=bot, server_id=server_id, channel_id=server_vc_id)
|
||||||
|
await rename_vc(bot, voice_channel=channel)
|
||||||
logger(f"{bot.user} ist online")
|
else:
|
||||||
await rename_vc(bot=bot, voice_channel=channel)
|
logger("Reconnected to discord gateway, this wont disturb your current ride")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bot.run(config["token"])
|
bot.run(config["token"])
|
||||||
@@ -23,12 +30,12 @@ except:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
TODO
|
TODO
|
||||||
- Only choose connections in the future
|
- 1024 embed limit
|
||||||
- discord reconnection handling
|
- automatic reload of operators
|
||||||
- Automatic transfer
|
|
||||||
- discord status
|
- discord status
|
||||||
- text announcements
|
- text announcements
|
||||||
- voice announcements
|
- voice announcements
|
||||||
- improved error handling (retry connection)
|
- improved error handling (retry connection)
|
||||||
- multi language support
|
- multi language support
|
||||||
|
- random = False
|
||||||
'''
|
'''
|
||||||
+30
-19
@@ -1,6 +1,7 @@
|
|||||||
import requests
|
import requests
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from src.utils import logger, config, get_train_name, convert_iso_string
|
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:
|
def get_random_stop_id() -> str:
|
||||||
assigned_station = random.choice(stations)
|
assigned_station = random.choice(stations)
|
||||||
req = f"{endpoint}/api/v1/geocode?text={assigned_station}"
|
req = f"{endpoint}/api/v1/geocode"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(req, headers=headers)
|
response = requests.get(req, params={"text": assigned_station}, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
@@ -35,34 +36,43 @@ def get_random_stop_id() -> str:
|
|||||||
return entry["id"]
|
return entry["id"]
|
||||||
|
|
||||||
def get_random_connection(stop_id: str) -> str:
|
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
|
cursor = None
|
||||||
count = 20
|
max_pages = 5
|
||||||
|
min_results = 5
|
||||||
|
trip_ids = []
|
||||||
|
all_stop_times = []
|
||||||
|
|
||||||
for _ in range(max_pages):
|
for _ in range(max_pages):
|
||||||
params = f"stopId={stop_id}&n={count}"
|
params = {
|
||||||
|
"stopId": stop_id,
|
||||||
|
"n": 20,
|
||||||
|
"time": now,
|
||||||
|
}
|
||||||
if cursor:
|
if cursor:
|
||||||
params += f"&pageCursor={cursor}"
|
params["pageCursor"] = cursor
|
||||||
|
|
||||||
req = f"{endpoint}/api/v1/stoptimes?{params}"
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(req, headers=headers)
|
response = requests.get(f"{endpoint}/api/v5/stoptimes", params=params, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
print(e)
|
print(e)
|
||||||
return None
|
break
|
||||||
|
|
||||||
trip_ids = []
|
|
||||||
stop_times = data.get("stopTimes", [])
|
stop_times = data.get("stopTimes", [])
|
||||||
|
all_stop_times.extend(stop_times)
|
||||||
|
|
||||||
for entry in 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"]
|
trip_id = entry["tripId"]
|
||||||
if entry["mode"] in blacklist:
|
if entry["mode"] in blacklist:
|
||||||
continue
|
continue
|
||||||
trip_ids.append(trip_id)
|
trip_ids.append(entry["tripId"])
|
||||||
|
|
||||||
if len(trip_ids) >= 5:
|
if len(trip_ids) >= min_results:
|
||||||
break
|
break
|
||||||
|
|
||||||
cursor = data.get("nextPageCursor")
|
cursor = data.get("nextPageCursor")
|
||||||
@@ -74,22 +84,23 @@ def get_random_connection(stop_id: str) -> str:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
trip_id = random.choice(trip_ids)
|
trip_id = random.choice(trip_ids)
|
||||||
for trip in stop_times:
|
|
||||||
if trip.get("tripId") == trip_id:
|
from_station = None
|
||||||
from_station = trip.get("place").get("name")
|
for entry in all_stop_times:
|
||||||
|
if entry.get("tripId") == trip_id:
|
||||||
|
from_station = entry.get("place", {}).get("name")
|
||||||
break
|
break
|
||||||
|
|
||||||
print(from_station)
|
|
||||||
return {
|
return {
|
||||||
"trip_id": trip_id,
|
"trip_id": trip_id,
|
||||||
"from_station": from_station
|
"from_station": from_station
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_trip_details(trip_id: str, from_station: str) -> dict:
|
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:
|
try:
|
||||||
response = requests.get(req, headers=headers)
|
response = requests.get(req, params={"tripId": trip_id}, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
emoji_list = {
|
emoji_list = {
|
||||||
"Fallback": "💺",
|
"Fallback": "💺",
|
||||||
"BUS": "🚎",
|
"BUS": "🚎",
|
||||||
|
"COACH": "🚎",
|
||||||
"TRAM": "🚈",
|
"TRAM": "🚈",
|
||||||
"REGIONAL_RAIL": "🚊",
|
"REGIONAL_RAIL": "🚊",
|
||||||
"HIGHSPEED_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",
|
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/ODEG-Logo_Neu.svg/960px-ODEG-Logo_Neu.svg.png",
|
||||||
"color": 0x00745C
|
"color": 0x00745C
|
||||||
},
|
},
|
||||||
"Nederlandse Spoorwegen": {
|
"NS": {
|
||||||
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Logo_NS.svg/960px-Logo_NS.svg.png",
|
"logo": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Logo_NS.svg/960px-Logo_NS.svg.png",
|
||||||
"color": 0X00337F,
|
"color": 0X00337F,
|
||||||
"slogan": ["Goed op weg", "Welkom in de trein van morgen", "Veilig, Vlug, Voordelig", "we haben een serious probleem", "Neuken in de keuken"]
|
"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 Regio AG Bayern": OPERATORS["db_bayern"],
|
||||||
"DB Fernverkehr AG": OPERATORS["db_allgemein"],
|
"DB Fernverkehr AG": OPERATORS["db_allgemein"],
|
||||||
"DB Regio AG NRW": 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 Südost": OPERATORS["db_allgemein"],
|
||||||
"DB Regio AG Nordost": OPERATORS["db_allgemein"],
|
"DB Regio AG Nordost": OPERATORS["db_allgemein"],
|
||||||
"DB Regio AG Mitte": OPERATORS["db_allgemein"],
|
"DB Regio AG Mitte": OPERATORS["db_allgemein"],
|
||||||
"SBB GmbH": OPERATORS["SBB"],
|
"SBB GmbH": OPERATORS["SBB"],
|
||||||
"Schweizerische Bundesbahnen SBB": OPERATORS["SBB"],
|
"Schweizerische Bundesbahnen SBB": OPERATORS["SBB"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+25
-9
@@ -1,26 +1,22 @@
|
|||||||
import discord
|
import discord
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta, date
|
||||||
|
|
||||||
from src.api import transitous
|
from src.utils import logger, channel_formatting, choose_connection
|
||||||
from src.utils import logger, channel_formatting
|
|
||||||
|
|
||||||
_scheduled_task: asyncio.Task | None = None
|
_scheduled_task: asyncio.Task | None = None
|
||||||
|
|
||||||
async def rename_vc(bot: discord.Bot, voice_channel, from_scheduler: bool = False):
|
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():
|
if not from_scheduler and _scheduled_task and not _scheduled_task.done():
|
||||||
_scheduled_task.cancel()
|
_scheduled_task.cancel()
|
||||||
|
|
||||||
station_id = transitous.get_random_stop_id()
|
trip = choose_connection()
|
||||||
connection = transitous.get_random_connection(station_id)
|
|
||||||
trip = transitous.get_trip_details(connection["trip_id"], connection["from_station"])
|
|
||||||
|
|
||||||
arrival = trip["arrival"]
|
arrival = trip["arrival"]
|
||||||
long_name = trip["long_name"]
|
long_name = trip["long_name"]
|
||||||
|
|
||||||
print("-----------------")
|
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"Betreiber: {trip["agency"]}, Typ: {trip["mode"]}")
|
||||||
logger(f"Versuche Namen zu ändern, wenn nichts passiert bin ich im cooldown... (warte bis zu 10min!)")
|
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!")
|
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 json
|
||||||
import os
|
import os
|
||||||
|
import importlib
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import src.data.operators as operators
|
import src.data.operators as operators
|
||||||
from src.data.emojis import emoji_list
|
from src.data.emojis import emoji_list
|
||||||
|
|
||||||
|
_operator_mtime = None
|
||||||
|
|
||||||
with open("config.json", "r") as file:
|
with open("config.json", "r") as file:
|
||||||
config = json.load(file)
|
config = json.load(file)
|
||||||
@@ -16,8 +19,19 @@ def logger(msg, log_type="info") -> str:
|
|||||||
if status == "FATAL":
|
if status == "FATAL":
|
||||||
os._exit(1)
|
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:
|
def convert_iso_string(isostring) -> str:
|
||||||
|
timezone = config.get("timezone", "Europe/Berlin")
|
||||||
dt = datetime.fromisoformat(isostring.replace('Z', '+00:00'))
|
dt = datetime.fromisoformat(isostring.replace('Z', '+00:00'))
|
||||||
|
dt = dt.astimezone(ZoneInfo(timezone))
|
||||||
|
|
||||||
if dt.second >= 30:
|
if dt.second >= 30:
|
||||||
dt += timedelta(minutes=1)
|
dt += timedelta(minutes=1)
|
||||||
|
|
||||||
@@ -43,7 +57,25 @@ def get_train_name(train_name: str, mode: str) -> str:
|
|||||||
|
|
||||||
return train
|
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:
|
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"]
|
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"])
|
logo = op_data.get("logo", operators.OPERATORS["fallback"]["logo"])
|
||||||
|
|||||||
Reference in New Issue
Block a user