Skip to content

Instantly share code, notes, and snippets.

@marcodejongh
Last active February 28, 2023 23:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcodejongh/759ac0ea111a20e683f36bca3bf80eb5 to your computer and use it in GitHub Desktop.
Save marcodejongh/759ac0ea111a20e683f36bca3bf80eb5 to your computer and use it in GitHub Desktop.
/*
Keeps checking the spirit of tasmania booking page for new available ferries.
I run this script in the chrome developer tools console with this page open:
https://www.spiritoftasmania.com.au/my-booking#?booking=XXXXX&lastname=YYYYY&step=ReturnFare&version=2
To open chrome devtools press: Option + ⌘ + J (on macOS), or Shift + CTRL + J (on Windows/Linux) then click the console tab.
You need to be on the page because of browser security policies, but technically these requests dont require a browser env
and could also be run in a nodejs script.
When the script finds an available ferry it spawns a notification, so make sure you have notifications turned on for chrome and
havent turned on "do not disturb mode". After having success once the script stops refreshing, so it will have to be
executed again if you want to continue searching.
Alternatively you can set superObnoxiousMusicMode to true which will make the tab play a sound as well.
Handy for when you're not behind your computer.
*/
(() => {
const superObnoxiousMusicMode = false;
// How often we should check for new ferries in minutes
const CHECKING_INTERVAL_IN_MINUTES = 1;
// Update this with the dates you want
const datesIWant = [
{ date: "2023-03-13T00:00:00", day: false, night: true },
{ date: "2023-03-14T00:00:00", day: true, night: true },
{ date: "2023-03-15T00:00:00", day: true, night: true },
];
/* Get the ferriesrequest object from the my-booking page
by going to the network panel in the dev tools and looking for a call to /prices
(To open press: Option + ⌘ + J (on macOS), or Shift + CTRL + J (on Windows/Linux) then click the network tab).
It'll usually only show requests since opening, so you can make it do another request manually by switching to a future
month and then back to the month you want.
Once done then click on the latest /prices request
there click "view source" which should give you the raw json blob
copy the json and paste it over undefined so it should like:
const ferriesRequest = {
lots of json data.
};
Make sure the prices request is made in the view that has the dates you are looking for.
If for example you're looking at week view, it won't be able to find dates outside of that week.
Basically, this script just reruns the API that fills the my-booking date selector table thingy.
<nerd-rant>
I probably could have made it nicer by making the actual UI refresh
and navigate through the UI if looking at multiple months.
then scanning the UI for the desired dates, but that sounded way harder and couldn't be bothered.
</nerd-rant>
*/
const ferriesRequest = undefined;
if(!ferriesRequest) {
throw new Error("You forgot to copy over your ferries request, see instructions in comments");
}
const musicParse = function(f) {
return eval("for(var t=0,S='RIFF_oO_WAVEfmt " + atob('EAAAAAEAAQBAHwAAQB8AAAEACAA') + "data';++t<3e5;)S+=String.fromCharCode(" + f + ")");
};
const music = function() {
var audio, formula;
formula = '(t<<3)*[8/9,1,9/8,6/5,4/3,3/2,0][[0xd2d2c8,0xce4088,0xca32c8,0x8e4009][t>>14&3]>>(0x3dbe4688>>((t>>10&15)>9?18:t>>10&15)*3&7)*3&7]&255';
audio = new Audio("data:audio/wav;base64," + (btoa(musicParse(formula))));
return audio.play();
};
if (!Notification.permission || Notification.permission !== "granted") {
Notification.requestPermission();
}
let checkingInterval = undefined;
const checkFerries = () => {
console.log("Fetching ferries");
fetch("https://www.spiritoftasmania.com.au/umbraco/api/ibp/prices", {
headers: {
"Content-Type": "application/json; charset=utf-8",
// Note to future me or other users. IF the rest api starts 500ing it's most likely because
// the jsbreakingchangeversion is no longer supported. It appears that a jsbreakingchangeversion header
// is how the spirit of tasmania backend handles rest api versioning (gross I know ;)). To fix this
// look at the headers of the /prices request in your network pane and copy over the jsbreakingchangeversion
// since we're copy pasting the whole request json in here anyway most likely that should be enough.
jsbreakingchangeversion: 20221208,
},
body: JSON.stringify(ferriesRequest),
method: "post",
})
.then((res) => res.json())
.then((res) => {
const resultsIWant = res.results.filter((item) => {
const dateIWantMetaData = datesIWant.find(
({ date }) => date === item.date,
);
if (!dateIWantMetaData) {
return false;
}
return (
(dateIWantMetaData.day &&
item.daySailings.length > 0 &&
item.daySailings[0].isSoldOut === false) ||
(dateIWantMetaData.night &&
item.nightSailings.length > 0 &&
item.nightSailings[0].isSoldOut === false)
);
});
console.log(`Fetched ${res.results.length} ferries`);
console.log(
`Of those results, we've found ${
resultsIWant.length
} available ferries`,
);
if (resultsIWant.length > 0) {
try {
new Notification("Ferry available!!!", {
requireInteraction: true,
});
if (superObnoxiousMusicMode) {
music();
}
} catch (err) {
console.error(err);
}
alert("Ferry I want available!!!");
try {
$(".month-toggle").click();
} catch (err) {
console.error('Didnt find the month toggle');
}
clearInterval(checkingInterval);
} else {
console.log(
`The ferries you are looking for are still sold out, try again in ${CHECKING_INTERVAL_IN_MINUTES} minutes`,
);
}
});
};
checkingInterval = setInterval(
checkFerries,
CHECKING_INTERVAL_IN_MINUTES * 60 * 1000,
);
checkFerries();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment