Skip to content

Instantly share code, notes, and snippets.

@derianpt
Last active February 3, 2024 14:15
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save derianpt/42a954131ca6f1d6d3f29436d1b5c847 to your computer and use it in GitHub Desktop.
activesg badminton booking scripts
// ==UserScript==
// @name activesg - single court for 2 hrs
// @namespace blah
// @version 0.6.5
// @description activesg court booking
// @match https://members.myactivesg.com/*
// @copyright 2017+, naresh,Gavin,Kent
// @require http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js
// ==/UserScript==
//StartTime: in 24H format and must >= 10
//CourtPrecedence: higher index has higher precedence
//var cfg = {Venue:"Bukit Gombak Sports Hall", StartTime:11, MaxStartTime:11};
var cfg = { Venue: "Delta Sports Hall", StartTime: 18, MaxStartTime: 19 };
//var cfg = {Venue:"Jurong East Sports Hall", StartTime:18, MaxStartTime:18};
//var cfg = {Venue:"Bukit View Secondary School Hall", StartTime:12, MaxStartTime:20};
var venuePrefs = {};
venuePrefs['Delta Sports Hall'] = { CourtPrecedence: [1, 5, 6, 4, 2, 3], GoodEnoughIndex: 5 };
venuePrefs['Delta Sports Hall'] = { CourtPrecedence: [1, 2, 3, 4], GoodEnoughIndex: 3 };
venuePrefs['Delta Sports Hall'] = { CourtPrecedence: [1, 6, 7, 5, 2, 3, 4], GoodEnoughIndex: 1 };
$(document).ready(function () {
var form = $("form#formTimeslots");
if (form.length > 0) {
//check venue id
var selectedVenue = $("#facVenueSelection > option[selected='selected']");
if (selectedVenue.length === 0) {
selectedVenue = $("p.item-desc-subtitle");
}
if (selectedVenue.length > 0 && selectedVenue.text() !== cfg.Venue) {
var newName = selectedVenue.text();
console.log(selectedVenue.val() + ":" + newName);
cfg.VenuePref = getVenuePref(newName);
if (typeof cfg.VenuePref !== "undefined") {
cfg.Venue = newName;
}
}
if (typeof cfg.VenuePref === "undefined") {
console.log("VenueName:" + cfg.Venue);
cfg.VenuePref = getVenuePref(cfg.Venue);
}
if (!book_2hrs(form)) {
if ($(".logged-in-red").length > 0) {
if (confirm("Failed to find courts for two consecutive hours, try again?")) {
window.location.pathname = "/facilities";
}
}
else {
//session expired, need relogin
window.location.pathname = "/auth";
}
}
return;
}
form = $("form");
var formId = form.attr("id");
if (formId === "formFacFilter" || formId === "formQuickBookSearch") {
setValue();
return;
}
else if (formId === "formCartPayment") {
console.log("Booked " + $(".facility-cart-entry").length + " Courts");
return;
}
console.log("pathname='" + window.location.pathname + "'");
console.log("formId='" + formId + "'");
if (window.location.pathname === "/cart") {
//no court is added to cart, redirect to facilities bookings
window.location.pathname = "/facilities";
}
if (window.location.pathname.indexOf("process") > 0) {
//https://members.myactivesg.com/facilities/processStandardBooking/59265c62ffaa599cde44ea3d0f11e53a
try {
eval("var result = " + $("pre").html() + ";");
//{"message":"Your bookings have been saved.","method":"confirm","confirm":"Your items are added to cart. Would you like to go to shopping cart?","redirect":"https:\/\/members.myactivesg.com\/cart"}
if (typeof result.redirect !== 'undefined') {
console.log("Redirecting to :" + result.redirect);
}
//{"code":7208,"message":"Sorry, you have exceeded your booking limit.","method":"alert"}
else {
eval(result.method + "('[" + result.code + "]" + result.message + "')");
}
}
catch (err) {
}
window.location.pathname = "/cart";
}
if (window.location.pathname === "/profile") {
window.location.pathname = "/facilities";
}
});
function setValue() {
var days = { "Mon": "1", "Tue": "2", "Wed": "3", "Thu": "4", "Fri": "5", "Sat": "6", "Sun": "7" };
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
//choose activity type
var activityTypeSelector = $("select#activity_filter");
var activityType = "18";
//set value
activityTypeSelector.val(activityType);
//set display value
var activityTypeName = activityTypeSelector.find("option").filter(function (index) { return $(this).val() === activityType; }).text();
$("#activity_filter_chosen > a > span").html(activityTypeName);
var venueSelector = $("select#venue_filter");
var venueOption = venueSelector.find("option").filter(function (index) { return $(this).text() === cfg.Venue; });
if (venueOption.length > 0) {
var venueId = venueOption.val();
//set value
venueSelector.val(venueId);
//set display value
$("#venue_filter_chosen > a > span").html(cfg.Venue);
}
else {
window.alert("Invalid Venue Name!!");
}
var book_on = new Date(new Date().setDate(new Date().getDate() + 15));
var date = ("" + book_on).slice(0, 15).replace(' ', ", ");
if ($("select#day_filter").length > 0) {
$("select#day_filter").val(days[date.split(",")[0]]);
}
var date_str = date.split(", ")[0] + ", " + book_on.getDate() + " " + months[book_on.getMonth()] + " " + book_on.getFullYear();
$("input#date_filter").val(date_str);
}
function getVenuePref(venueName) {
var venuePref = venuePrefs[venueName];
if ((typeof venuePref === "undefined")) {
console.log("returns default venue pref");
venuePref = { CourtPrecedence: [], GoodEnoughIndex: 999 };
}
return venuePref;
}
function searchCourt(form, startTime, endTime) {
//format is "Court <Number>;<venueId?>;<slotId>;<startTime>;<endTime>"
//e.g. "Court 01;50;128450;15:00:00;16:00:00"
//the value should ends($=) with ";<endTime>"
//console.log("Searching for " + startTime + ":00:00 - "+ endTime + ":00:00");
var slots = form.find("div.row.timeslot-grid input[type='checkbox'][value$=';" + endTime + ":00:00']");
if (slots.length > 1 && cfg.VenuePref.CourtPrecedence.length > 0) {
var topCourt = null;
var topPrecedence = -1;
$.each(slots, function (i, item) {
var courtNumber = parseInt(item.value.substring(7, 9));
var p = cfg.VenuePref.CourtPrecedence.lastIndexOf(courtNumber);
//console.log("Court "+courtNumber + " Pref = " + p);
if (p > topPrecedence) {
//console.log("BetterChoice:Time=" + startTime + ":00:00" + " Court " + item.CourtNumber);
topCourt = item;
topPrecedence = p;
if (topPrecedence >= cfg.VenuePref.GoodEnoughIndex) return false;
}
});
return $(topCourt);
}
else if (slots.length > 0) {
return $(slots[0]);
}
else {
return null;
}
}
//book one court for two consecutive hours
function book_2hrs(form) {
var time0 = cfg.StartTime;
cfg.MaxStartTime = cfg.MaxStartTime < cfg.StartTime ? cfg.StartTime : cfg.MaxStartTime;
while (time0 <= cfg.MaxStartTime) {
var time1 = time0 + 1;
var time2 = time0 + 2;
var court1 = searchCourt(form, time1, time2);
if (court1 === null) {
//no court available for the second hour, move start time 2 hrs after
time0 = time2;
continue;
}
var court2 = searchCourt(form, time0, time1);
if (court2 === null) {
var time3 = time0 + 3;
//no court available for the first hour, try search the third hour
court2 = searchCourt(form, time2, time3);
if (court2 === null) {
time0 = time3;
continue;
}
}
//select court and submit
court1.prop("checked", true);
court2.prop("checked", true);
form.submit();
//console.log("Selected:"+court1.val());
//console.log("Selected:"+court2.val());
return true;
}
return false;
}
// ==UserScript==
// @name activesg - single court for 2 hrs
// @namespace blah
// @version 0.6.5
// @description activesg court booking
// @match https://members.myactivesg.com/*
// @copyright 2017+, naresh,Gavin,Kent
// @require http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js
// ==/UserScript==
//StartTime: in 24H format and must >= 10
//CourtPrecedence: higher index has higher precedence
//var cfg = {Venue:"Bukit Gombak Sports Hall", StartTime:11, MaxStartTime:11};
var cfg = { Venue: "Zhangde Primary School Hall", StartTime: 18, MaxStartTime: 18 };
//var cfg = {Venue:"Jurong East Sports Hall", StartTime:18, MaxStartTime:18};
//var cfg = {Venue:"Bukit View Secondary School Hall", StartTime:12, MaxStartTime:20};
var venuePrefs = {};
venuePrefs['Zhangde Primary School Hall'] = { CourtPrecedence: [3, 1, 4, 2], GoodEnoughIndex: 3 };
venuePrefs['Gan Eng Seng Secondary School Hall'] = { CourtPrecedence: [3, 1, 4, 2], GoodEnoughIndex: 3 };
venuePrefs['Delta Sports Hall'] = { CourtPrecedence: [3, 1, 4, 2], GoodEnoughIndex: 3 };
$(document).ready(function () {
var form = $("form#formTimeslots");
if (form.length > 0) {
//check venue id
var selectedVenue = $("#facVenueSelection > option[selected='selected']");
if (selectedVenue.length === 0) {
selectedVenue = $("p.item-desc-subtitle");
}
if (selectedVenue.length > 0 && selectedVenue.text() !== cfg.Venue) {
var newName = selectedVenue.text();
console.log(selectedVenue.val() + ":" + newName);
cfg.VenuePref = getVenuePref(newName);
if (typeof cfg.VenuePref !== "undefined") {
cfg.Venue = newName;
}
}
if (typeof cfg.VenuePref === "undefined") {
console.log("VenueName:" + cfg.Venue);
cfg.VenuePref = getVenuePref(cfg.Venue);
}
if (!book_2hrs(form)) {
if ($(".logged-in-red").length > 0) {
if (confirm("Failed to find courts for two consecutive hours, try again?")) {
window.location.pathname = "/facilities";
}
}
else {
//session expired, need relogin
window.location.pathname = "/auth";
}
}
return;
}
form = $("form");
var formId = form.attr("id");
if (formId === "formFacFilter" || formId === "formQuickBookSearch") {
setValue();
return;
}
else if (formId === "formCartPayment") {
console.log("Booked " + $(".facility-cart-entry").length + " Courts");
return;
}
console.log("pathname='" + window.location.pathname + "'");
console.log("formId='" + formId + "'");
if (window.location.pathname === "/cart") {
//no court is added to cart, redirect to facilities bookings
window.location.pathname = "/facilities";
}
if (window.location.pathname.indexOf("process") > 0) {
//https://members.myactivesg.com/facilities/processStandardBooking/59265c62ffaa599cde44ea3d0f11e53a
try {
eval("var result = " + $("pre").html() + ";");
//{"message":"Your bookings have been saved.","method":"confirm","confirm":"Your items are added to cart. Would you like to go to shopping cart?","redirect":"https:\/\/members.myactivesg.com\/cart"}
if (typeof result.redirect !== 'undefined') {
console.log("Redirecting to :" + result.redirect);
}
//{"code":7208,"message":"Sorry, you have exceeded your booking limit.","method":"alert"}
else {
eval(result.method + "('[" + result.code + "]" + result.message + "')");
}
}
catch (err) {
}
window.location.pathname = "/cart";
}
if (window.location.pathname === "/profile") {
window.location.pathname = "/facilities";
}
});
function setValue() {
var days = { "Mon": "1", "Tue": "2", "Wed": "3", "Thu": "4", "Fri": "5", "Sat": "6", "Sun": "7" };
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
//choose activity type
var activityTypeSelector = $("select#activity_filter");
var activityType = "18";
//set value
activityTypeSelector.val(activityType);
//set display value
var activityTypeName = activityTypeSelector.find("option").filter(function (index) { return $(this).val() === activityType; }).text();
$("#activity_filter_chosen > a > span").html(activityTypeName);
var venueSelector = $("select#venue_filter");
var venueOption = venueSelector.find("option").filter(function (index) { return $(this).text() === cfg.Venue; });
if (venueOption.length > 0) {
var venueId = venueOption.val();
//set value
venueSelector.val(venueId);
//set display value
$("#venue_filter_chosen > a > span").html(cfg.Venue);
}
else {
window.alert("Invalid Venue Name!!");
}
var book_on = new Date(new Date().setDate(new Date().getDate() + 15));
var date = ("" + book_on).slice(0, 15).replace(' ', ", ");
if ($("select#day_filter").length > 0) {
$("select#day_filter").val(days[date.split(",")[0]]);
}
var date_str = date.split(", ")[0] + ", " + book_on.getDate() + " " + months[book_on.getMonth()] + " " + book_on.getFullYear();
$("input#date_filter").val(date_str);
}
function getVenuePref(venueName) {
var venuePref = venuePrefs[venueName];
if ((typeof venuePref === "undefined")) {
console.log("returns default venue pref");
venuePref = { CourtPrecedence: [], GoodEnoughIndex: 999 };
}
return venuePref;
}
function searchCourt(form, startTime, endTime) {
//format is "Court <Number>;<venueId?>;<slotId>;<startTime>;<endTime>"
//e.g. "Court 01;50;128450;15:00:00;16:00:00"
//the value should ends($=) with ";<endTime>"
//console.log("Searching for " + startTime + ":00:00 - "+ endTime + ":00:00");
var slots = form.find("div.row.timeslot-grid input[type='checkbox'][value$=';" + endTime + ":00:00']");
if (slots.length > 1 && cfg.VenuePref.CourtPrecedence.length > 0) {
var topCourt = null;
var topPrecedence = -1;
$.each(slots, function (i, item) {
var courtNumber = parseInt(item.value.substring(7, 9));
var p = cfg.VenuePref.CourtPrecedence.lastIndexOf(courtNumber);
//console.log("Court "+courtNumber + " Pref = " + p);
if (p > topPrecedence) {
//console.log("BetterChoice:Time=" + startTime + ":00:00" + " Court " + item.CourtNumber);
topCourt = item;
topPrecedence = p;
if (topPrecedence >= cfg.VenuePref.GoodEnoughIndex) return false;
}
});
return $(topCourt);
}
else if (slots.length > 0) {
return $(slots[0]);
}
else {
return null;
}
}
//book one court for two consecutive hours
function book_2hrs(form) {
var time0 = cfg.StartTime;
cfg.MaxStartTime = cfg.MaxStartTime < cfg.StartTime ? cfg.StartTime : cfg.MaxStartTime;
while (time0 <= cfg.MaxStartTime) {
var time1 = time0 + 1;
var time2 = time0 + 2;
var court1 = searchCourt(form, time1, time2);
if (court1 === null) {
//no court available for the second hour, move start time 2 hrs after
time0 = time2;
continue;
}
var court2 = searchCourt(form, time0, time1);
if (court2 === null) {
var time3 = time0 + 3;
//no court available for the first hour, try search the third hour
court2 = searchCourt(form, time2, time3);
if (court2 === null) {
time0 = time3;
continue;
}
}
//select court and submit
court1.prop("checked", true);
court2.prop("checked", true);
form.submit();
//console.log("Selected:"+court1.val());
//console.log("Selected:"+court2.val());
return true;
}
return false;
}
@alibabadoufu
Copy link

Hi,

Good job.

May I know how can I use this script?

Thank you.

@LeonardLooi
Copy link

Hi Derian,

Thanks for the amazing script. I have emailed you to get in touch with you, wish you hear from you soon.

@Jarrettgohh
Copy link

Wait this script is usable?

@Roninfyc
Copy link

Roninfyc commented May 7, 2021

what a script. just bumped into this. may I know how to setup this to my pc ?

@Never2019
Copy link

Can this be detected by activesg?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment