Skip to content

Instantly share code, notes, and snippets.

@jimmygle
Last active March 2, 2021 03:51
Show Gist options
  • Save jimmygle/293417ed2acd61deec0c53993c12a360 to your computer and use it in GitHub Desktop.
Save jimmygle/293417ed2acd61deec0c53993c12a360 to your computer and use it in GitHub Desktop.
Creates and shows reservations for the anytime fitness reserver tool at reserve.anytimefitness.com. It takes too long, so this is a simple ruby script to do it via CLI.
#!/usr/bin/env ruby
require 'net/http'
require 'uri'
require 'json'
require 'thor'
require 'date'
require 'pry'
ENV['THOR_SILENCE_DEPRECATION'] = '1'
class GymReservation < Thor
desc "reserve DATE at HOUR", 'eg today at noon, tue at 4pm, monday at 2p'
def reserve(date, at, hour)
abort('ERROR: Format must be "DATE at HOUR" (eg today at 5pm)') if at != 'at'
date_string = "%s %s %s" % [ _convert_date(date).to_s, _convert_hour(hour), Time.now.strftime("%:z") ]
parsed = DateTime.strptime(date_string, "%Y-%m-%d %l%P %Z")
epoch = parsed.to_time.to_i * 1000
reserved = _reserve(epoch)
if reserved['error']
puts "ERROR: #{reserved['error']}"
puts "Edit reservations: https://reserve.anytimefitness.com/reservations"
else
puts "Reservation successfully set for: #{parsed.strftime('%A, %B %-d, %Y at %-I%P')}"
end
end
desc 'reservations', 'shows current reservations'
def reservations
rs = _reservations
next_reservation = Time.at(rs['results'].first['start_int'] / 1000).utc.localtime
if next_reservation > Time.now
puts "Next reservation: #{next_reservation.strftime('%A, %B %-d, %Y at %-I%P')}"
else
puts "No current reservations."
end
end
no_commands do
def _convert_date(date)
case date
when 'today'
return Date.today
when 'tomorrow'
return Date.today.next_day
else
begin
d = Date.parse(date)
if ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', 'monday', 'tuesday', 'thursday', 'friday', 'saturday', 'sunday'].include?(date.downcase)
return Date.today > d ? d + 7 : d
end
return d
rescue => error
puts "Invalid date: #{date}"
puts "Must be: today, tomorrow, mon, tuesday, or 2021-01-01 formats"
exit!
end
end
end
def _convert_hour(hour)
h = hour.gsub(/^(\d{1,2})(p|a)$/, '\\1\\2m')
unless h =~ /^\d{1,2}(am|pm)?$/
puts "Invalid hour: #{hour}"
puts "Must be: 9, 9a, 9am, 9p, 9pm"
exit!
end
h += 'am' if h =~ /^\d{1,2}$/
return h
end
def _reserve(date)
uri = URI.parse("https://api.muuvlabs.com/anytime/reservations")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["Authority"] = "api.muuvlabs.com"
request["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Safari/537.36"
request["Cookieproxy"] = "---POPULATE ME FROM BROWSER SESSION---"
request["Accept"] = "*/*"
request["Sec-Gpc"] = "1"
request["Origin"] = "https://reserve.anytimefitness.com"
request["Sec-Fetch-Site"] = "cross-site"
request["Sec-Fetch-Mode"] = "cors"
request["Sec-Fetch-Dest"] = "empty"
request["Referer"] = "https://reserve.anytimefitness.com/"
request["Accept-Language"] = "en-US,en;q=0.9"
request.body = {club_ident: "---GET THIS FROM BROWSER---", start_int: date}.to_json
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
return JSON.parse(response.body)
end
def _reservations
uri = URI.parse("https://api.muuvlabs.com/anytime/reservations?include_club=1&per_page=500&ran=1614655270209")
request = Net::HTTP::Get.new(uri)
request.content_type = "application/json"
request["Authority"] = "api.muuvlabs.com"
request["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Safari/537.36"
request["Cookieproxy"] = "---POPULATE ME FROM BROWSER SESSION---"
request["Accept"] = "*/*"
request["Sec-Gpc"] = "1"
request["Origin"] = "https://reserve.anytimefitness.com"
request["Sec-Fetch-Site"] = "cross-site"
request["Sec-Fetch-Mode"] = "cors"
request["Sec-Fetch-Dest"] = "empty"
request["Referer"] = "https://reserve.anytimefitness.com/"
request["Accept-Language"] = "en-US,en;q=0.9"
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
return JSON.parse(response.body)
end
end
end
GymReservation.start(ARGV)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment