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