This repository has been archived by the owner on Dec 11, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbook.py
128 lines (111 loc) · 4.19 KB
/
book.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from requests_html import HTMLSession
from urllib.parse import parse_qs, urlparse
from time import sleep
from datetime import datetime, timedelta
from dateparser import parse as parse_datetime
import argparse
import sys
# iBooking studio IDs
STUDIOS = {
"gløshaugen": 306,
"dragvoll": 307,
"portalen": 308,
"dmmh": 402,
"moholt": 540,
}
# iBooking activity IDs
ACTIVITIES = {"egentrening": 419380}
def log_in(session: HTMLSession, username: str, password: str) -> None:
session.post(
"https://www.sit.no/trening",
data={"name": username, "pass": password, "form_id": "user_login"},
).raise_for_status()
def get_token(session: HTMLSession) -> str:
response = session.get("https://www.sit.no/trening/gruppe")
response.raise_for_status()
ibooking_src = response.html.find("#ibooking-iframe", first=True).attrs["src"]
return parse_qs(urlparse(ibooking_src).query)["token"][0]
def get_schedule(session: HTMLSession, studio: int, token: str) -> dict:
response = session.get(
"https://ibooking.sit.no/webapp/api/Schedule/getSchedule",
params={"studios": studio, "token": token},
)
response.raise_for_status()
return response.json()
def add_booking(session: HTMLSession, token: str, class_id: int) -> None:
session.post(
"https://ibooking.sit.no/webapp/api/Schedule/addBooking",
data={"classId": class_id, "token": token},
).raise_for_status()
def book(session: HTMLSession, training_start: datetime, studio: int) -> bool:
token = get_token(session)
schedule = get_schedule(session, studio, token)
for day in schedule["days"]:
if parse_datetime(day["date"]).date() == training_start.date():
for training_class in day["classes"]:
if (
training_class["activityId"] == ACTIVITIES["egentrening"]
and parse_datetime(training_class["from"]) == training_start
):
booking_start = parse_datetime(training_class["bookingOpensAt"])
if datetime.now() < booking_start:
opens_in = booking_start - datetime.now()
print(
f"Booking opens in {str(opens_in).split('.')[0]}. Going to sleep ..."
)
sleep(opens_in.total_seconds())
add_booking(session, token, training_class["id"])
return True
return False
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Book training slots (egentrening) at Sit.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument("username", type=str, help="Sit username (email)")
parser.add_argument("password", type=str, help="Sit password")
parser.add_argument(
"--time",
type=str,
metavar="hhmm",
help="start time (example: 0730)",
required=True,
)
parser.add_argument(
"--days",
type=int,
default=2,
help="number of days until training slot (0 is today)",
)
parser.add_argument(
"--studio",
type=str,
default="gløshaugen",
choices=STUDIOS.keys(),
help="studio",
)
parser.add_argument("--max-tries", type=int, default=2, help="max number of tries")
args = parser.parse_args()
training_start = (datetime.now() + timedelta(days=args.days)).replace(
hour=int(args.time[:2]), minute=int(args.time[2:]), second=0, microsecond=0
)
success = False
current_try = 1
while current_try <= args.max_tries:
session = HTMLSession()
try:
log_in(session, args.username, args.password)
success = book(session, training_start, STUDIOS[args.studio])
print(
"Slot booked!"
if success
else "Could not find a training slot matching the provided parameters."
)
break
except Exception:
if current_try == args.max_tries:
print("An error occurred.")
finally:
session.close()
current_try += 1
sys.exit(0 if success else 1)