Initial commit

This commit is contained in:
augustin64 2023-12-01 19:07:59 +01:00
commit 8625622002
6 changed files with 211 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
archive
har
src/config.py
**/__pycache__

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
requests

45
src/classes.py Normal file
View 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
View 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
View 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
View 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)