Created
March 4, 2026 12:40
-
-
Save AndrewAubury/6fb63eab8a7a5b07eab487f0dcf6c05c to your computer and use it in GitHub Desktop.
PureGym Attendance Worker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * PureGym Attendance – Cloudflare Worker (AUTHENTICATED) | |
| * | |
| * Set credentials as secrets: | |
| * wrangler secret put PUREGYM_EMAIL | |
| * wrangler secret put PUREGYM_PIN | |
| */ | |
| /** | |
| * Gym list | |
| * Key = output name | |
| * Value = gymId (int) | |
| */ | |
| const GYMS = { | |
| "dunstable": 111, | |
| "luton": 462, | |
| }; | |
| /** | |
| * Authenticate and return Bearer token | |
| */ | |
| async function authenticate(email, pin) { | |
| const body = new URLSearchParams({ | |
| grant_type: "password", | |
| username: email, | |
| password: pin, | |
| scope: "pgcapi", | |
| client_id: "ro.client", | |
| }); | |
| const res = await fetch("https://auth.puregym.com/connect/token", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/x-www-form-urlencoded", | |
| "User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0", | |
| }, | |
| body, | |
| }); | |
| if (!res.ok) { | |
| throw new Error(`Auth failed: ${res.status}`); | |
| } | |
| const json = await res.json(); | |
| return json.access_token; | |
| } | |
| /** | |
| * Fetch attendance for one gym | |
| */ | |
| async function fetchAttendance(token, gymId) { | |
| const res = await fetch( | |
| `https://capi.puregym.com/api/v2/gymSessions/gym?gymId=${gymId}`, | |
| { | |
| headers: { | |
| "Authorization": `Bearer ${token}`, | |
| "User-Agent": "PureGym/1523 CFNetwork/1312 Darwin/21.0.0", | |
| }, | |
| } | |
| ); | |
| if (!res.ok) { | |
| return 0; | |
| //throw new Error(`Attendance failed (${gymId}): ${res.status}`); | |
| } | |
| const json = await res.json(); | |
| if(json.TotalPeopleInGym == null){ | |
| return 0; | |
| }else{ | |
| return json.TotalPeopleInGym; | |
| } | |
| } | |
| export default { | |
| async fetch(request, env, ctx) { | |
| try { | |
| const token = await authenticate( | |
| env.PUREGYM_EMAIL, | |
| env.PUREGYM_PIN | |
| ); | |
| const result = {}; | |
| await Promise.all( | |
| Object.entries(GYMS).map(async ([name, gymId]) => { | |
| try { | |
| result[name] = await fetchAttendance(token, gymId); | |
| } catch { | |
| result[name] = null; | |
| } | |
| }) | |
| ); | |
| return new Response(JSON.stringify(result, null, 2), { | |
| headers: { | |
| "Content-Type": "application/json", | |
| "Cache-Control": "no-store", | |
| }, | |
| }); | |
| } catch (err) { | |
| return new Response( | |
| JSON.stringify({ error: err.message }), | |
| { status: 500 } | |
| ); | |
| } | |
| }, | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment