Initial commit
This commit is contained in:
commit
8625622002
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
archive
|
||||||
|
har
|
||||||
|
src/config.py
|
||||||
|
**/__pycache__
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
requests
|
45
src/classes.py
Normal file
45
src/classes.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
from utils import raiseDiscord
|
||||||
|
|
||||||
|
class Travel():
|
||||||
|
def __init__(self, data):
|
||||||
|
self.orderId = data["orderId"]
|
||||||
|
self.serviceItemId = data["serviceItemId"]
|
||||||
|
self.dvNumber = data["dvNumber"]
|
||||||
|
self.origin = data["origin"]
|
||||||
|
self.destination = data["destination"]
|
||||||
|
self.departureDateTime = data["departureDateTime"]
|
||||||
|
self.arrivalDateTime = data["arrivalDateTime"]
|
||||||
|
|
||||||
|
self.travelClass = data["travelClass"]
|
||||||
|
self.trainNumber = data["trainNumber"]
|
||||||
|
self.coachNumber = data["coachNumber"]
|
||||||
|
self.seatNumber = data["seatNumber"]
|
||||||
|
|
||||||
|
self.reservationDate = data["reservationDate"]
|
||||||
|
self.travelConfirmed = data["travelConfirmed"] # CONFIRMED, TOO_EARLY_TO_CONFIRM
|
||||||
|
self.travelStatus = data["travelStatus"]
|
||||||
|
|
||||||
|
def confirm(self, session, headers):
|
||||||
|
"""
|
||||||
|
https://www.maxjeune-tgvinoui.sncf/api/public/reservation/travel-confirm
|
||||||
|
{"marketingCarrierRef":"{Référence}","trainNumber":"{trainNumber}","departureDateTime":"2023-01-01T01:01:00.000"}
|
||||||
|
"""
|
||||||
|
r = session.post(
|
||||||
|
"https://www.maxjeune-tgvinoui.sncf/api/public/reservation/travel-confirm",
|
||||||
|
headers=headers,
|
||||||
|
json={
|
||||||
|
"marketingCarrierRef": self.dvNumber,
|
||||||
|
"trainNumber": self.trainNumber,
|
||||||
|
"departureDateTime": self.departureDateTime
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (r.status_code >= 300 or r.status_code < 200):
|
||||||
|
raiseDiscord(
|
||||||
|
"An error occurred during travel auto confirmation",
|
||||||
|
travel=self,
|
||||||
|
req=r
|
||||||
|
)
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
12
src/example_config.py
Normal file
12
src/example_config.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Numéro de carte TGVMax, 17 chiffres
|
||||||
|
card_number="..."
|
||||||
|
|
||||||
|
# Change très fréquemment (1 fois par heure ?)
|
||||||
|
authorization = "Bearer ..."
|
||||||
|
|
||||||
|
cookies = "didomi_token=...; euconsent-v2=...; sticky__authentication=...; _dd_s=..."
|
||||||
|
|
||||||
|
|
||||||
|
# Discord Webhooks
|
||||||
|
error_url = "https://discord.com/api/webhooks/..."
|
||||||
|
success_url = "https://discord.com/api/webhooks/..."
|
88
src/main.py
Normal file
88
src/main.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import utils
|
||||||
|
import config
|
||||||
|
from classes import Travel
|
||||||
|
|
||||||
|
"""
|
||||||
|
https://www.maxjeune-tgvinoui.sncf/api/public/subscription/summary
|
||||||
|
{"cardNumber": {CARDNUMBER}}
|
||||||
|
|
||||||
|
https://www.maxjeune-tgvinoui.sncf/api/public/reservation/travel-consultation
|
||||||
|
{"cardNumber": {CARDNUMBER},"startDate":"2023-01-01T01:01:01.001Z"}
|
||||||
|
|
||||||
|
https://www.maxjeune-tgvinoui.sncf/api/public/reservation/travel-confirm
|
||||||
|
{"marketingCarrierRef":"{Référence}","trainNumber":"{trainNumber}","departureDateTime":"2023-01-01T01:01:00.000"}
|
||||||
|
|
||||||
|
https://www.maxjeune-tgvinoui.sncf/api/public/reservation/cancel-reservation
|
||||||
|
{"travelsInfo":[{"marketingCarrierRef":"{Référence}","orderId":"{orderId}","customerName":"{NomAssocié}","trainNumber":"{trainNumber}","departureDateTime":"2023-01-01T01:01:00.000"}]}
|
||||||
|
"""
|
||||||
|
|
||||||
|
CARDNUMBER=config.card_number
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0",
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Accept-Language": "fr,fr-FR;q=0.8,en;q=0.5,en-US;q=0.3", # MANDATORY
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": config.authorization,
|
||||||
|
"Cookie": config.cookies,
|
||||||
|
}
|
||||||
|
|
||||||
|
def r_to_data(r):
|
||||||
|
assert r.status_code >= 200 and r.status_code < 300
|
||||||
|
return json.loads(r.content.decode("utf-8"))
|
||||||
|
|
||||||
|
def summary(s, headers):
|
||||||
|
return s.post(
|
||||||
|
"https://www.maxjeune-tgvinoui.sncf/api/public/subscription/summary",
|
||||||
|
headers=headers,
|
||||||
|
json={"cardNumber": CARDNUMBER}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def travel_consultation(s, headers, date_time=None):
|
||||||
|
if date_time is None:
|
||||||
|
date_time = datetime.utcnow()
|
||||||
|
|
||||||
|
return s.post(
|
||||||
|
"https://www.maxjeune-tgvinoui.sncf/api/public/reservation/travel-consultation",
|
||||||
|
headers=headers,
|
||||||
|
json={
|
||||||
|
"cardNumber": CARDNUMBER,
|
||||||
|
"startDate": date_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def check_confirmed(travel, s, headers):
|
||||||
|
travels = [Travel(i) for i in r_to_data(travel_consultation(s, headers))]
|
||||||
|
for t in travels:
|
||||||
|
if t.dvNumber == travel.dvNumber and t.departureDateTime == travel.departureDateTime and t.trainNumber == travel.trainNumber and t.travelConfirmed != "CONFIRMED":
|
||||||
|
utils.raiseDiscord(
|
||||||
|
"The tentative of confirmation did not succeed",
|
||||||
|
travel=t,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def confirm_all(s, headers):
|
||||||
|
travels = [Travel(i) for i in r_to_data(travel_consultation(s, headers))]
|
||||||
|
|
||||||
|
now = datetime.utcnow()
|
||||||
|
for travel in travels:
|
||||||
|
if datetime.fromisoformat(travel.departureDateTime) >= now:
|
||||||
|
print(travel)
|
||||||
|
print(travel.travelConfirmed)
|
||||||
|
if (travel.travelConfirmed != "CONFIRMED" and travel.travelConfirmed != "TOO_EARLY_TO_CONFIRM"):
|
||||||
|
travel.confirm(s, headers)
|
||||||
|
if check_confirmed(travel, s, headers):
|
||||||
|
utils.successDiscord(travel)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
s = requests.Session()
|
61
src/utils.py
Normal file
61
src/utils.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import requests
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from config import error_url, success_url
|
||||||
|
|
||||||
|
color_red = 16711680
|
||||||
|
color_green = 65280
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def raiseDiscord(message, travel=None, req=None):
|
||||||
|
data = {
|
||||||
|
"username": "TGVMax AutoConfirm",
|
||||||
|
"avatar_url": "https://cdn.discordapp.com/attachments/894238990633427034/1180197752911696082/tgvmax.png",
|
||||||
|
"embeds":
|
||||||
|
[{
|
||||||
|
"title": "Erreur lors de la confirmation automatique",
|
||||||
|
"description": message,
|
||||||
|
"color": color_red,
|
||||||
|
"fields": []
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
if travel is not None:
|
||||||
|
departureDateTime = datetime.fromisoformat(travel.departureDateTime)
|
||||||
|
data["embeds"][0]["fields"].append({
|
||||||
|
"name": f"Travel {travel.dvNumber}",
|
||||||
|
"value": departureDateTime.strftime("%d %b. %Hh%M")
|
||||||
|
})
|
||||||
|
if req is not None:
|
||||||
|
try:
|
||||||
|
data["embeds"][0]["fields"].append({
|
||||||
|
"name": f"Erreur {req.status_code}",
|
||||||
|
"value": req.content[:200].decode("utf-8")
|
||||||
|
})
|
||||||
|
except TypeError:
|
||||||
|
data["embeds"][0]["fields"].append({
|
||||||
|
"name": f"Erreur {req.status_code}",
|
||||||
|
"value": "dunno"
|
||||||
|
})
|
||||||
|
|
||||||
|
requests.post(error_url, json=data)
|
||||||
|
|
||||||
|
|
||||||
|
def successDiscord(travel):
|
||||||
|
departureDateTime = datetime.fromisoformat(travel.departureDateTime)
|
||||||
|
data = {
|
||||||
|
"username": "TGVMax AutoConfirm",
|
||||||
|
"avatar_url": "https://cdn.discordapp.com/attachments/894238990633427034/1180197752911696082/tgvmax.png",
|
||||||
|
"embeds":
|
||||||
|
[{
|
||||||
|
"title": "Trajet validé automatiquement",
|
||||||
|
"color": color_green,
|
||||||
|
"fields": [{
|
||||||
|
"name": f"Travel {travel.dvNumber}",
|
||||||
|
"value": departureDateTime.strftime("%d %b. %Hh%M")
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
requests.post(error_url, json=data)
|
Loading…
Reference in New Issue
Block a user