feat: Make notifier and program async

Using asyncio library, notification are now trigerred
asynchronously.
This commit is contained in:
kbe
2025-07-21 20:29:44 +02:00
parent 3a378c03a6
commit d71bfff10e
3 changed files with 83 additions and 8 deletions

View File

@@ -2,6 +2,7 @@
import logging import logging
import traceback import traceback
import asyncio
from crossfit_booker import CrossFitBooker from crossfit_booker import CrossFitBooker
if __name__ == "__main__": if __name__ == "__main__":
@@ -30,5 +31,5 @@ if __name__ == "__main__":
exit(1) exit(1)
# Start the continuous booking loop # Start the continuous booking loop
booker.run() asyncio.run(booker.run())
logging.info("Script completed") logging.info("Script completed")

View File

@@ -363,7 +363,9 @@ class CrossFitBooker:
# First check if can_join is true (primary condition) # First check if can_join is true (primary condition)
if user_info.get("can_join", False): if user_info.get("can_join", False):
activity_name = session.get("name_activity") activity_name = session.get("name_activity")
logging.debug(f"Session is bookable: {activity_name} can_join is True") activity_date = session.get("start_timestamp", "Unknown date")
activity_time = activity_date.split(" ")[1] if " " in activity_date else "Unknown time"
logging.debug(f"Session is bookable: {activity_name} on {activity_date} at {activity_time} - can_join is True")
return True return True
# If can_join is False, check if there's a booking window # If can_join is False, check if there's a booking window
@@ -435,7 +437,7 @@ class CrossFitBooker:
logging.error(f"Failed to check session: {str(e)} - Session: {session}") logging.error(f"Failed to check session: {str(e)} - Session: {session}")
return False return False
def run_booking_cycle(self, current_time: datetime) -> None: async def run_booking_cycle(self, current_time: datetime) -> None:
""" """
Run one cycle of checking and booking sessions. Run one cycle of checking and booking sessions.
@@ -487,7 +489,7 @@ class CrossFitBooker:
if not session_time.tzinfo: if not session_time.tzinfo:
session_time = pytz.timezone(TIMEZONE).localize(session_time) session_time = pytz.timezone(TIMEZONE).localize(session_time)
session_details = f"{session['name_activity']} at {session_time.strftime('%Y-%m-%d %H:%M')}" session_details = f"{session['name_activity']} at {session_time.strftime('%Y-%m-%d %H:%M')}"
self.notifier.notify_session_booking(session_details) await self.notifier.notify_session_booking(session_details)
logging.info(f"Notified about found preferred session: {session_details}") logging.info(f"Notified about found preferred session: {session_details}")
# Notify about upcoming sessions # Notify about upcoming sessions
@@ -496,7 +498,7 @@ class CrossFitBooker:
if not session_time.tzinfo: if not session_time.tzinfo:
session_time = pytz.timezone(TIMEZONE).localize(session_time) session_time = pytz.timezone(TIMEZONE).localize(session_time)
session_details = f"{session['name_activity']} at {session_time.strftime('%Y-%m-%d %H:%M')}" session_details = f"{session['name_activity']} at {session_time.strftime('%Y-%m-%d %H:%M')}"
self.notifier.notify_upcoming_session(session_details, 1) # Days until is 1 for tomorrow await self.notifier.notify_upcoming_session(session_details, 1) # Days until is 1 for tomorrow
logging.info(f"Notified about upcoming session: {session_details}") logging.info(f"Notified about upcoming session: {session_details}")
# Book sessions (preferred first) # Book sessions (preferred first)
@@ -507,12 +509,12 @@ class CrossFitBooker:
if self.book_session(session["id_activity_calendar"]): if self.book_session(session["id_activity_calendar"]):
# Send notification after successful booking # Send notification after successful booking
session_details = f"{session['name_activity']} at {session_time.strftime('%Y-%m-%d %H:%M')}" session_details = f"{session['name_activity']} at {session_time.strftime('%Y-%m-%d %H:%M')}"
self.notifier.notify_session_booking(session_details) await self.notifier.notify_session_booking(session_details)
logging.info(f"Successfully booked {session_type} session at {session_time}") logging.info(f"Successfully booked {session_type} session at {session_time}")
else: else:
logging.error(f"Failed to book {session_type} session at {session_time} - Session: {session}") logging.error(f"Failed to book {session_type} session at {session_time} - Session: {session}")
def run(self) -> None: async def run(self) -> None:
""" """
Main execution loop. Main execution loop.
""" """
@@ -531,7 +533,7 @@ class CrossFitBooker:
logging.info(f"Current time: {current_time}") logging.info(f"Current time: {current_time}")
# Always run booking cycle to check for preferred sessions and notify # Always run booking cycle to check for preferred sessions and notify
self.run_booking_cycle(current_time) await self.run_booking_cycle(current_time)
# Run booking cycle at the target time for actual booking # Run booking cycle at the target time for actual booking
target_time_str = current_time.strftime("%H:%M") target_time_str = current_time.strftime("%H:%M")

72
docs/waiting_list.json Normal file
View File

@@ -0,0 +1,72 @@
curl 'https://sport.nubapp.com/api/v4/activities/activity-calendar/19291431/basicInfo?app_version=5.09.21^&id_application=81560887' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Accept-Language: en-GB,en;q=0.8,fr-FR;q=0.5,fr;q=0.3' \
-H 'Accept-Encoding: gzip, deflate, br, zstd' \
-H 'Referer: https://box.resawod.com/' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Nubapp-Origin: user_apps' \
-H 'Origin: https://box.resawod.com' \
-H 'Sec-GPC: 1' \
-H 'Connection: keep-alive' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: cross-site' \
-H 'Priority: u=0' \
-H 'TE: trailers'
{
"message": "All right! Here is your data.",
"data": {
"activity_calendar": {
"id_activity_calendar": 19291431,
"name_activity": "CONDITIONING LOUVRE 3",
"description": "\\u003Cp\\u003EWod Condi, de la simplicit\\u00e9 mais beaucoup d\\u0027intensit\\u00e9... des erg mais pas seulement, des mouvements de CrossFit qui vous permettrons d\\u0027am\\u00e9liorer vos capacit\\u00e9s a\\u00e9robies\\u003C\\/p\\u003E",
"id_activity": 43932,
"id_category_activity": 677,
"start_timestamp": "2025-07-23 18:30:00",
"end_timestamp": "2025-07-23 19:15:00",
"n_inscribed": 12,
"n_capacity": 12,
"n_waiting_list": 3,
"n_capacity_waiting_list": 8,
"id_trainer": null,
"is_course": false,
"cancelled": false,
"guest_info": {
"can_join": true,
"available_booking_options": [],
"errors": 0,
"errors_by_memberships": [],
"join_as_normal_user": false,
"vouchers": [],
"voucher_autopay": false,
"unableToBookUntilDate": null,
"unableToBookUntilTime": null,
"best_booking_option": {
"type": 2,
"price": 0,
"membershipId": null,
"discountId": null,
"discountValue": null
},
"price": 0,
"price_befdis": 0,
"user_attending": false,
"user_waiting": false
},
"facilities": [],
"image": null,
"color": "#a74cd6",
"max_guests": 0,
"guest_prices": {
"1": 0,
"2": 0,
"3": 0
},
"id_language": null
}
},
"success": true,
"status": 200
}