From 59af14e6ff2ef86a60229bd01db49061b70836a5 Mon Sep 17 00:00:00 2001 From: Kaaninchen <124433727+kaaninchen@users.noreply.github.com> Date: Mon, 17 Aug 2026 12:49:35 +0200 Subject: [PATCH] transitous rewrite: next_stop improvements --- data.json | 698 ------------------------------------------ src/api/transitous.py | 34 +- src/config.py | 2 +- src/data/operators.py | 1 + src/dc/embeds.py | 3 +- src/utils.py | 48 ++- 6 files changed, 39 insertions(+), 747 deletions(-) delete mode 100644 data.json diff --git a/data.json b/data.json deleted file mode 100644 index a68ed54..0000000 --- a/data.json +++ /dev/null @@ -1,698 +0,0 @@ -{ - "duration": 1440, - "startTime": "2026-08-16T21:25:00Z", - "endTime": "2026-08-16T21:49:00Z", - "transfers": 0, - "id": "CogBCgI1NBIiMjAyNjA4MTZfMjM6MjVfbmwtT3Blbk9WXzM3Njc3ODE5OBoRbmwtT3Blbk9WXzM5ODA3NDch/ilVouwlSkAp147iHHX0E0AyEW5sLU9wZW5PVl8zOTc5OTIwOZRIopdRMEpAQcGxZ89lmhNASKzViNQGUMzgiNQGWgZTVUJXQVlgAQ==", - "legs": [ - { - "mode": "SUBWAY", - "from": { - "name": "Amsterdam, Gein", - "stopId": "nl-OpenOV_3980747", - "parentId": "nl-OpenOV_NL:S:30009530", - "importance": 0.018040798604488373, - "lat": 52.296284, - "lon": 4.988728000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "departure": "2026-08-16T21:25:00Z", - "scheduledDeparture": "2026-08-16T21:25:00Z", - "scheduledTrack": "1", - "track": "1", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NOT_ALLOWED", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS train", - "descriptionText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS trains to Zuid or at Spaklerweg for Overamstel. Details: gvb.nl" - } - ], - "modes": [ - "SUBWAY", - "BUS" - ] - }, - "to": { - "name": "Amsterdam, Centraal Station", - "stopId": "nl-OpenOV_3979920", - "parentId": "nl-OpenOV_NL:S:30009500", - "importance": 0.17953550815582275, - "lat": 52.377489999999995, - "lon": 4.900779000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:49:00Z", - "scheduledArrival": "2026-08-16T21:49:00Z", - "vertexType": "TRANSIT", - "pickupType": "NOT_ALLOWED", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Neem M52 naar Zuid voor RAI en de richting Isolatorweg. Details: gvb.nl/zomermetro|-- Take M52 to Zuid for RAI and the direction Isolatorweg", - "descriptionText": "Neem M52 naar Zuid voor RAI en de richting Isolatorweg. Details: gvb.nl/zomermetro|-- Take M52 to Zuid for RAI and the direction Isolatorweg. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "HIGHSPEED_RAIL", - "LONG_DISTANCE", - "NIGHT_RAIL", - "REGIONAL_RAIL", - "SUBWAY", - "TRAM", - "BUS", - "FERRY" - ] - }, - "duration": 1440, - "startTime": "2026-08-16T21:25:00Z", - "endTime": "2026-08-16T21:49:00Z", - "scheduledStartTime": "2026-08-16T21:25:00Z", - "scheduledEndTime": "2026-08-16T21:49:00Z", - "realTime": true, - "scheduled": true, - "interlineWithPreviousLeg": false, - "headsign": "Centraal Station", - "tripFrom": { - "name": "Amsterdam, Gein", - "stopId": "nl-OpenOV_3980747", - "parentId": "nl-OpenOV_NL:S:30009530", - "importance": 0.018040798604488373, - "lat": 52.296284, - "lon": 4.988728000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "departure": "2026-08-16T21:25:00Z", - "scheduledDeparture": "2026-08-16T21:25:00Z", - "scheduledTrack": "1", - "track": "1", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NOT_ALLOWED", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS train", - "descriptionText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS trains to Zuid or at Spaklerweg for Overamstel. Details: gvb.nl" - } - ], - "modes": [ - "SUBWAY", - "BUS" - ] - }, - "tripTo": { - "name": "Amsterdam, Centraal Station", - "stopId": "nl-OpenOV_3979920", - "parentId": "nl-OpenOV_NL:S:30009500", - "importance": 0.17953550815582275, - "lat": 52.377489999999995, - "lon": 4.900779000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:49:00Z", - "scheduledArrival": "2026-08-16T21:49:00Z", - "vertexType": "TRANSIT", - "pickupType": "NOT_ALLOWED", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Neem M52 naar Zuid voor RAI en de richting Isolatorweg. Details: gvb.nl/zomermetro|-- Take M52 to Zuid for RAI and the direction Isolatorweg", - "descriptionText": "Neem M52 naar Zuid voor RAI en de richting Isolatorweg. Details: gvb.nl/zomermetro|-- Take M52 to Zuid for RAI and the direction Isolatorweg. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "HIGHSPEED_RAIL", - "LONG_DISTANCE", - "NIGHT_RAIL", - "REGIONAL_RAIL", - "SUBWAY", - "TRAM", - "BUS", - "FERRY" - ] - }, - "routeId": "nl-OpenOV_152364", - "routeUrl": "", - "directionId": "0", - "routeColor": "fff200", - "routeTextColor": "000000", - "routeType": 1, - "agencyName": "GVB", - "agencyUrl": "http://www.gvb.nl/klantenservice", - "agencyFareUrl": "", - "agencyId": "GVB", - "tripId": "20260816_23:25_nl-OpenOV_376778198", - "routeShortName": "54", - "routeLongName": "Lijn 54", - "tripShortName": "", - "displayName": "54", - "cancelled": false, - "source": "nl_OpenOV.gtfs.zip/stop_times.txt:1582071:1582085", - "intermediateStops": [ - { - "name": "Amsterdam, Reigersbos", - "stopId": "nl-OpenOV_3979741", - "parentId": "nl-OpenOV_NL:S:30009528", - "importance": 0.018029676750302315, - "lat": 52.29557400000001, - "lon": 4.973636000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:26:00Z", - "departure": "2026-08-16T21:27:00Z", - "scheduledArrival": "2026-08-16T21:26:00Z", - "scheduledDeparture": "2026-08-16T21:27:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS train", - "descriptionText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS trains to Zuid or at Spaklerweg for Overamstel. Details: gvb.nl" - } - ], - "modes": [ - "SUBWAY", - "BUS" - ] - }, - { - "name": "Amsterdam, Station Holendrecht", - "stopId": "nl-OpenOV_3981303", - "parentId": "nl-OpenOV_NL:S:30009526", - "importance": 0.026576673611998558, - "lat": 52.29839300000001, - "lon": 4.959859000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:28:00Z", - "departure": "2026-08-16T21:29:00Z", - "scheduledArrival": "2026-08-16T21:28:00Z", - "scheduledDeparture": "2026-08-16T21:29:00Z", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS train", - "descriptionText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS trains to Zuid or at Spaklerweg for Overamstel. Details: gvb.nl" - } - ], - "modes": [ - "REGIONAL_RAIL", - "SUBWAY", - "BUS" - ] - }, - { - "name": "Amsterdam, Bullewijk", - "stopId": "nl-OpenOV_3981144", - "parentId": "nl-OpenOV_NL:S:30009524", - "importance": 0.017878592014312744, - "lat": 52.30693, - "lon": 4.952079, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:30:00Z", - "departure": "2026-08-16T21:31:00Z", - "scheduledArrival": "2026-08-16T21:30:00Z", - "scheduledDeparture": "2026-08-16T21:31:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS train", - "descriptionText": "Stap op Bijlmer ArenA over op NS-treinen naar Zuid of op Spaklerweg voor Overamstel. Details: gvb.nl --|Change at Bijlmer ArenA for NS trains to Zuid or at Spaklerweg for Overamstel. Details: gvb.nl" - } - ], - "modes": [ - "SUBWAY" - ] - }, - { - "name": "Amsterdam, Station Bijlmer ArenA", - "stopId": "nl-OpenOV_3980962", - "parentId": "nl-OpenOV_NL:S:30009522", - "importance": 0.04671318084001541, - "lat": 52.31261, - "lon": 4.946935, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:32:00Z", - "departure": "2026-08-16T21:32:00Z", - "scheduledArrival": "2026-08-16T21:32:00Z", - "scheduledDeparture": "2026-08-16T21:32:00Z", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Neem NS-treinen naar Zuid of stap op Spaklerweg over voor Overamstel. Details: gvb.nl/zomermetro --|Take NS trains to Zuid or change at Spak", - "descriptionText": "Neem NS-treinen naar Zuid of stap op Spaklerweg over voor Overamstel. Details: gvb.nl/zomermetro --|Take NS trains to Zuid or change at Spaklerweg for Overamstel. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "LONG_DISTANCE", - "COACH", - "NIGHT_RAIL", - "REGIONAL_RAIL", - "SUBWAY", - "BUS" - ] - }, - { - "name": "Amsterdam, Strandvliet", - "stopId": "nl-OpenOV_3981329", - "parentId": "nl-OpenOV_NL:S:30009520", - "importance": 0.017878592014312744, - "lat": 52.31868399999999, - "lon": 4.941375000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:33:00Z", - "departure": "2026-08-16T21:34:00Z", - "scheduledArrival": "2026-08-16T21:33:00Z", - "scheduledDeparture": "2026-08-16T21:34:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Spaklerweg over voor Overamstel of op Amstel voor RAI. Details: gvb.nl/zomermetro –|Change at Spaklerweg for Overamstel or at Amstel", - "descriptionText": "Stap op Spaklerweg over voor Overamstel of op Amstel voor RAI. Details: gvb.nl/zomermetro –|Change at Spaklerweg for Overamstel or at Amstel for RAI. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "SUBWAY" - ] - }, - { - "name": "Duivendrecht, Station Duivendrecht", - "stopId": "nl-OpenOV_3979812", - "parentId": "nl-OpenOV_NL:S:30009551", - "importance": 0.018022045493125916, - "lat": 52.323895, - "lon": 4.936262000000002, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:35:00Z", - "departure": "2026-08-16T21:35:00Z", - "scheduledArrival": "2026-08-16T21:35:00Z", - "scheduledDeparture": "2026-08-16T21:35:00Z", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-09T15:42:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-09T15:42:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Neem NS-treinen naar Zuid of stap op Spaklerweg over voor Overamstel. Details: gvb.nl/zomermetro --|Take NS trains to Zuid or change at Spak", - "descriptionText": "Neem NS-treinen naar Zuid of stap op Spaklerweg over voor Overamstel. Details: gvb.nl/zomermetro --|Take NS trains to Zuid or change at Spaklerweg for Overamstel. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "SUBWAY", - "BUS" - ] - }, - { - "name": "Amsterdam, Van der Madeweg", - "stopId": "nl-OpenOV_3981387", - "parentId": "nl-OpenOV_NL:S:30009516", - "importance": 0.0271453857421875, - "lat": 52.329903, - "lon": 4.930333000000001, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:36:00Z", - "departure": "2026-08-16T21:37:00Z", - "scheduledArrival": "2026-08-16T21:36:00Z", - "scheduledDeparture": "2026-08-16T21:37:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Stap op Spaklerweg over voor Overamstel of op Amstel voor RAI. Details: gvb.nl/zomermetro –|Change at Spaklerweg for Overamstel or at Amstel", - "descriptionText": "Stap op Spaklerweg over voor Overamstel of op Amstel voor RAI. Details: gvb.nl/zomermetro –|Change at Spaklerweg for Overamstel or at Amstel for RAI. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "SUBWAY", - "BUS" - ] - }, - { - "name": "Amsterdam, Spaklerweg", - "stopId": "nl-OpenOV_3980158", - "parentId": "nl-OpenOV_NL:S:30009518", - "importance": 0.02681240625679493, - "lat": 52.340239999999994, - "lon": 4.92107, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:39:00Z", - "departure": "2026-08-16T21:39:00Z", - "scheduledArrival": "2026-08-16T21:39:00Z", - "scheduledDeparture": "2026-08-16T21:39:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "modes": [ - "SUBWAY", - "BUS" - ] - }, - { - "name": "Amsterdam, Amstelstation", - "stopId": "nl-OpenOV_3980520", - "parentId": "nl-OpenOV_NL:S:30009514", - "importance": 0.052102621644735336, - "lat": 52.346489999999996, - "lon": 4.9175699999999996, - "level": 0.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:40:00Z", - "departure": "2026-08-16T21:41:00Z", - "scheduledArrival": "2026-08-16T21:40:00Z", - "scheduledDeparture": "2026-08-16T21:41:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "alerts": [ - { - "communicationPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "impactPeriod": [ - { - "start": "2026-07-04T04:00:00Z", - "end": "2026-08-16T23:00:00Z" - } - ], - "cause": "UNKNOWN_CAUSE", - "effect": "UNKNOWN_EFFECT", - "headerText": "Neem tram 23 voor RAI of bus 78 voor Overamstel. Details: gvb.nl/zomermetro. --|Take tram 23 for RAI or bus 78 for Overamstel. Details: gvb.nl/summermetro", - "descriptionText": "Neem tram 23 voor RAI of bus 78 voor Overamstel. Details: gvb.nl/zomermetro. --|Take tram 23 for RAI or bus 78 for Overamstel. Details: gvb.nl/summermetro" - } - ], - "modes": [ - "REGIONAL_RAIL", - "SUBWAY", - "TRAM", - "BUS" - ] - }, - { - "name": "Amsterdam, Wibautstraat", - "stopId": "nl-OpenOV_3980265", - "parentId": "nl-OpenOV_NL:S:30009512", - "importance": 0.027183683589100838, - "lat": 52.354332, - "lon": 4.9121879999999996, - "level": -2.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:42:00Z", - "departure": "2026-08-16T21:43:00Z", - "scheduledArrival": "2026-08-16T21:42:00Z", - "scheduledDeparture": "2026-08-16T21:43:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "modes": [ - "SUBWAY", - "TRAM", - "BUS" - ] - }, - { - "name": "Amsterdam, Weesperplein", - "stopId": "nl-OpenOV_3981336", - "parentId": "nl-OpenOV_NL:S:30009510", - "importance": 0.02798701450228691, - "lat": 52.361236999999996, - "lon": 4.907945, - "level": -2.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:44:00Z", - "departure": "2026-08-16T21:45:00Z", - "scheduledArrival": "2026-08-16T21:44:00Z", - "scheduledDeparture": "2026-08-16T21:45:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "modes": [ - "SUBWAY", - "TRAM", - "BUS" - ] - }, - { - "name": "Amsterdam, Waterlooplein", - "stopId": "nl-OpenOV_3980640", - "parentId": "nl-OpenOV_NL:S:30009508", - "importance": 0.027206193655729294, - "lat": 52.366985, - "lon": 4.9031400000000005, - "level": -2.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:46:00Z", - "departure": "2026-08-16T21:46:00Z", - "scheduledArrival": "2026-08-16T21:46:00Z", - "scheduledDeparture": "2026-08-16T21:46:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "modes": [ - "SUBWAY", - "TRAM", - "BUS" - ] - }, - { - "name": "Amsterdam, Nieuwmarkt", - "stopId": "nl-OpenOV_3981245", - "parentId": "nl-OpenOV_NL:S:30009502", - "importance": 0.02679653838276863, - "lat": 52.371914, - "lon": 4.901427000000001, - "level": -2.0, - "tz": "Europe/Brussels", - "arrival": "2026-08-16T21:47:00Z", - "departure": "2026-08-16T21:47:00Z", - "scheduledArrival": "2026-08-16T21:47:00Z", - "scheduledDeparture": "2026-08-16T21:47:00Z", - "scheduledTrack": "2", - "track": "2", - "vertexType": "TRANSIT", - "pickupType": "NORMAL", - "dropoffType": "NORMAL", - "cancelled": false, - "modes": [ - "SUBWAY" - ] - } - ], - "legGeometry": { - "points": "wd|vbBornoHN??fGFxa@?hQOzU?jFwBhF}ApDVhFLhg@^bi@LnDM|UBno@?bIKj[?vATxl@NpNFz`@D~j@?z`@?f]Fpd@Vl[?dGLjQVdGL|Jb@hQHlE\\rMnAxVb@|Id@jFzAlZhAtLv@vLjAvL?ZbAvLf@fGfBbSjAtL~Ib~@rClZvAjPd@lEdH|t@tCf\\`C`Tr@zJd@hFdA`IpBhQxBhQjEpX|AvLpCpXjCtWbGpn@zHnz@fBdR|A`TjAbSd@tWVvLWtM[`T_@|JmAhQaBhRcClP_DjQsEbT_DzKoD|JkD~J{E|J}BnE_DfG_DjFkBtBkFfHeFhGiGhGqHjG{OzLee@t\\{PvN_SnQW?eAz@cj@xf@g@\\aAz@a@ZgAz@e@z@u@\\qHfHap@nj@u@z@kAx@O\\e@?qCrCse@bc@_SrP_IdIiXbVeJdI}OxMsAxAaRpPmBxAq@x@q@z@yIdIkGjFeOxMuJbJ}Az@kCrCg@\\sAvA{HjGgGhGO?wXbV{FlFoWfU_d@h`@s`@p]oUjSsOzMoCrCkAx@_DrCeEpDmGfHmh@|e@sAx@kAz@sAvAyAxA{p@lk@u@z@q@z@gEpDsDrCkCrCw`@r\\{JbJqk@vg@qBxAil@pi@yBvBce@db@wAz@mBvA]z@u@\\e@x@u@\\cAz@}OvNwDpDaf@db@sAxAaCtBcTnQS\\}XfUqHjG{BtBaAz@u@x@oCvBkFnEwGfHw`@p]gb@l_@wX`Wu@\\iAvAkBxAgAz@wAvAqRlRgYdVyNvN_DrC?\\K?{FnEgSrPO?cj@|e@oDnDsBxAgm@ri@yAvAuJfI{f@bc@iBtBiAz@u@\\iBtBccA~}@wL`Kcj@th@wVbW_UfT_VdVwAvAgAz@eXxYoCtCyBrCW?k@x@u@z@{FhGkBrCeSjSmGhGuNtO{L~KqLbJoCtBeKbJkK`K_}@lcAW\\cAz@cAvA}@z@sAvAsj@hm@}h@th@wIbJwFjFuWt[}O~KcP`L_DrC{@x@w@z@_DrCcAz@cAz@kAx@gAxAsEpDU\\{AvAgc@l_@iUlSce@ha@_IdImBtByFnEea@r]e@z@wAx@kM|LaCtByBtBsCvBkCtByNzMa@Z}BvBuJdIs`@r]sj@|e@kiC`~Bos@hn@sfAxaA_\\~XoUlR{PzMcVnRyLfIqBz@iCxAqGpDeU|M}bAxj@eA\\{Az@ac@pSwBvAsEvBwDrCcIrDwBxAiA\\_DxAyIrDgOjG_MvCuNpEyUvDgJvCkGxAkNhHcj@fXk_Adf@gJnFiZvOkKnFyBz@ya@pSWZ}^rRyQ|LyIjG_M~Kkl@nk@sb@fb@wVfUaP~L}P~KwMlGuOdJqVhIwSpFcWfJgLpEwLnFgOjHga@nSsFtCs{@lc@eS~LaR~KkdA`i@ia@pSihA~i@c`@nScJpEgGrDcV`Li}@df@uOhIwf@dXsWzNwDxA_MnFmQjHufBxz@oLnFea@fWuJjGiGlFmFlF_DpDmDpDqCnDeEjGeEhG_ItNsY|o@sMvYgZzp@yF|KuE|KkF|KwG|KyDhGyBrC{FfHaHfHmLbKkHnE}FtCoDxAeExAeE|@iBz@mFz@eJ|@_Nb@oG@{JsA_DYeIuAiLgE_TyI_o@aY_NcGkCuAoAy@sEoC_HiEsDqCsIaHoJyJyBoCeEiFcMgPu^kc@qL{IqM_H}S_HkKqAqMsAaNDgSxCoHxAcMtDsR~LkHfHsCpDiBtBaAvBY?sAtBqEfHcCrCuE~Ja@z@oGvM_DdI_IdTkVnt@wBqC", - "precision": 6, - "length": 430 - }, - "bikesAllowed": true, - "wheelchairAccessible": "NOT_ACCESSIBLE", - "reservation": "NONE", - "alternatives": [] - } - ] -} \ No newline at end of file diff --git a/src/api/transitous.py b/src/api/transitous.py index 5a26c09..b255557 100644 --- a/src/api/transitous.py +++ b/src/api/transitous.py @@ -3,7 +3,7 @@ import random import json from datetime import datetime, timezone -from src.utils import logger, get_train_name, convert_iso_string, validate_connection +from src.utils import logger, get_train_name, validate_connection, parse_iso from src.config import config stations = config.connections.stations @@ -120,8 +120,8 @@ def get_random_stop_id() -> str | None: stop_ids_list = list(stop_ids.keys()) stops_string = ", ".join(stop_ids.values()) if len(stop_ids_list) > 1: - logger(f"Station '{assigned_station}' not found, choosing random from available: {stops_string}") - logger(f"No station associated as '{assigned_station}', choosing random from available") + logger(f"No station associated as '{assigned_station}', choosing random from similar named stations:") + logger({stops_string}) chosen_stop_id = random.choice(stop_ids_list) return chosen_stop_id @@ -209,8 +209,8 @@ def get_trip_details(random_connection: dict | None) -> dict | None: start_time = legs["startTime"] mode = legs["mode"] - arrival = convert_iso_string(end_time) - departure = convert_iso_string(start_time) + arrival_dt = parse_iso(end_time) + departure_dt = parse_iso(start_time) train_name = get_train_name(display_name, mode) if train_from == from_station: @@ -227,27 +227,27 @@ def get_trip_details(random_connection: dict | None) -> dict | None: "agency": legs["agencyName"], "route_color": legs.get("routeColor"), "duration": legs["duration"], - "departure": departure, - "arrival": arrival, + "departure": departure_dt.strftime("%H:%M"), + "arrival": arrival_dt.strftime("%H:%M"), "mode": mode, "stops": {} } - trip_details["stops"][train_from] = departure - departure_time = start_time + trip_details["stops"][train_from] = departure_dt + departure_time_iso = start_time for stop in legs["intermediateStops"]: - stop_arrival = convert_iso_string(stop["arrival"]) - trip_details["stops"][stop["name"]] = stop_arrival # not sure if that actually works but im too tired to question it + stop_arrival_dt = parse_iso(stop["arrival"]) + trip_details["stops"][stop["name"]] = stop_arrival_dt if stop.get("name") == from_station: - departure_time = stop["departure"] - trip_details["departure"] = convert_iso_string(departure_time) - trip_details["stops"][goes_to] = arrival + departure_time_iso = stop["departure"] + trip_details["departure"] = parse_iso(departure_time_iso).strftime("%H:%M") - valid = validate_connection(start_time, end_time, departure_time) + trip_details["stops"][goes_to] = arrival_dt + + valid = validate_connection(start_time, end_time, departure_time_iso) if not valid: return None - - logger(json.dumps(trip_details, indent=4, ensure_ascii=False)) + return trip_details diff --git a/src/config.py b/src/config.py index 160486c..33957b9 100644 --- a/src/config.py +++ b/src/config.py @@ -44,7 +44,7 @@ class Config: def _load_config() -> Config: with open("config.json", "r") as file: raw = json.load(file) - + return Config( discord=DiscordConfig(**raw["discord"]), connections=ConnectionsConfig(**raw["connections"]), diff --git a/src/data/operators.py b/src/data/operators.py index 68119cb..a3bd292 100644 --- a/src/data/operators.py +++ b/src/data/operators.py @@ -110,6 +110,7 @@ OPERATORS = { } OPERATOR_ALIASES = { + "Arverio BAyern GmbH": OPERATORS["Arverio Bayern"], "DB Regio AG Baden-Württemberg": OPERATORS["db_bawü"], "DB Regio Stuttgart GmbH": OPERATORS["db_bawü"], "Arverio Baden-Württemberg": OPERATORS["db_bawü"], diff --git a/src/dc/embeds.py b/src/dc/embeds.py index 2f9a070..a383f58 100644 --- a/src/dc/embeds.py +++ b/src/dc/embeds.py @@ -34,8 +34,7 @@ def build_info_embed() -> discord.Embed: stops = trip["stops"] - next_stop = get_next_station(trip["stops"]) - print(f"next_stop: {next_stop}") + next_stop = get_next_station(trip["stops"], trip["from"]) next_stop_station = None if next_stop: next_stop_station = next_stop.get("name") diff --git a/src/utils.py b/src/utils.py index e8611d2..2c42df2 100644 --- a/src/utils.py +++ b/src/utils.py @@ -10,7 +10,7 @@ import src.data.operators as operators from src.data.emojis import emoji_list _operator_mtime = None - +LOCAL_TZ = ZoneInfo(config.connections.timezone) def logger(msg, log_type="info") -> str: status = log_type.upper() @@ -60,14 +60,9 @@ def validate_connection(start_time: str, end_time: str, station_departure: str) return True -def convert_iso_string(isostring) -> str: - timezone = config.connections.timezone - dt = datetime.fromisoformat(isostring.replace('Z', '+00:00')) - dt = dt.astimezone(ZoneInfo(timezone)) - - if dt.second >= 30: - dt += timedelta(minutes=1) - return dt.strftime('%H:%M') +def parse_iso(iso_str: str) -> datetime: + dt = datetime.fromisoformat(iso_str.replace("Z", "+00:00")) + return dt.astimezone(LOCAL_TZ) def channel_formatting(mode: str) -> str: formatting = config.discord.formatting @@ -80,7 +75,7 @@ def channel_formatting(mode: str) -> str: return f"{emoji}{formatting}" def get_train_name(train_name: str, mode: str) -> str: - if mode == "BUS" or mode == "TRAM": + if mode == "BUS" or mode == "TRAM" or train_name.isdigit(): train = f"{mode.capitalize()} {train_name}" elif "(" in train_name: train = train_name.split(" (")[0] @@ -153,24 +148,19 @@ def get_sound_path(destination) -> str | None: return sound_path -def get_next_station(stops: dict) -> dict | None: - now = datetime.now() - today = datetime.today() - day_offset = 0 - previous_time = None - - for name, arrival_str in stops.items(): - arrival_time = datetime.strptime(arrival_str, "%H:%M").time() - - if previous_time is not None and arrival_time < previous_time: - day_offset += 1 - - arrival_dt = datetime.combine(today + timedelta(days=day_offset), arrival_time) - previous_time = arrival_time - +def get_next_station(stops: dict, train_from :str) -> dict | None: + now = datetime.now(LOCAL_TZ) + print(train_from) + for name, arrival_dt in stops.items(): if arrival_dt >= now: - return {"name": name, "arrival": arrival_str} - + if name == train_from: + return None + else: + return { + "name": name, + "arrival": arrival_dt.strftime("%H:%M") + } + return None def format_via_list(stops: dict) -> str: @@ -187,9 +177,9 @@ def format_stop_list(stops: dict, next_stop: str | None) -> list[tuple[str, str] for name, stop_arrival in stops.items(): if name == next_stop: - line = f"• __{name} ({stop_arrival} Uhr__)" + line = f"• __{name}__ ({stop_arrival.strftime("%H:%M")} Uhr)" else: - line = f"• {name} ({stop_arrival} Uhr)" + line = f"• {name} ({stop_arrival.strftime("%H:%M")} Uhr)" if field_length + len(line) + 1 > 1024: route_page_name = "Route" if part == 1 else "Route (Fortsetzung)"