Skip to content

Instantly share code, notes, and snippets.

@Rovack
Last active May 3, 2024 12:38
Show Gist options
  • Save Rovack/51e0fb558ee0fa4ce0e2cd5f0ab17cb1 to your computer and use it in GitHub Desktop.
Save Rovack/51e0fb558ee0fa4ce0e2cd5f0ab17cb1 to your computer and use it in GitHub Desktop.
A simple script that waits for tickets to become available for the Harry Potter Studio Tour in London, and grabs them
// Note that this has some limitations, such as looking specifically for adult tickets,
// looking for the given days only in the nearest month that has availability,
// and always choosing the earliest time if several are found within the desired dates.
function setAdultTickets(adultTicketsWanted) {
const adultTicketsCount = parseInt($('.quantity-control.row > input')[0].value, 10);
const ticketChangeIterations = Math.abs(adultTicketsWanted - adultTicketsCount);
const ticketChangeButton = $(`.quantity-control.row > button.typcn-${adultTicketsCount < adultTicketsWanted ? 'plus' : 'minus'}`)[0];
for (let i = 0; i < ticketChangeIterations; i++) {
ticketChangeButton.click();
}
}
function playSound(src) {
return new Promise((resolve) => {
const audio = new Audio(src);
audio.onended = resolve;
audio.play();
});
}
function repeatHeyListen() {
playSound('https://www.myinstants.com/media/sounds/hey_listen.mp3')
.then(repeatHeyListen);
}
function waitForAvailability() {
return new Promise((resolve) => {
setTimeout(() => {
const availableEls = $('.calendar>.row:not(.blankLoader) .calendar-body .day.available'), isLoading = $('.calendar-modal[data-component=eventTimeModal] .modal-content > .loading-mask.hide').length === 0;
if (isLoading) {
return waitForAvailability()
.then((res) => resolve(res));
}
resolve(availableEls);
}, 1000);
});
}
function playSounds() {
playSound('https://www.myinstants.com/media/sounds/mlg-airhorn.mp3')
.then(() => playSound('https://www.myinstants.com/media/sounds/sound-9______.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/ps_1.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/wrong-answer-sound-effect.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/lalalalala.swf.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/tuturu_1.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/hallelujahshort.swf.mp3'))
.then(repeatHeyListen);
}
function addTicketsToBasket(dayElement) {
dayElement.click();
setTimeout(() => waitForAvailability()
.then(() => {
$('.ui-control.button.select-time')[0].click();
setTimeout(() => {
$('.typcn.typcn-shopping-cart.ng-binding')[0].click();
}, 2000);
}), 2000);
}
function checkForTickets(datesWanted=[6, 7, 8], adultTicketsWanted=2, checkFrequency=15) {
setAdultTickets(adultTicketsWanted);
function check() {
$('.shared-calendar-button').click();
waitForAvailability()
.then(availableEls => {
console.log(new Date(), 'Availability loaded. Checking for relevant dates...');
for (let i = 0; i < availableEls.length; i++) {
const day = parseInt(availableEls[i].innerText, 10);
console.log('Day', day, 'is available...');
if (datesWanted.includes(day)) {
console.log('Found tickets!!!!!');
playSounds();
addTicketsToBasket(availableEls[i]);
return;
}
}
console.log(`Relevant dates not yet available. Will check again in ${checkFrequency} seconds.`);
$('#page > div:nth-child(11) > div.modal.info-modal.w-auto-c > div > div.close').click();
setTimeout(check, checkFrequency * 1000);
});
};
check();
}
@gokhanalpdogan
Copy link

gokhanalpdogan commented Apr 16, 2024

Hello there,

Sorry for this dumb questions but really i need to ask :/

i've modified the script in which days i want to buy. (14 - 15 may) here is the script code;


// Note that this has some limitations, such as looking specifically for adult tickets,
// looking for the given days only in the nearest month that has availability,
// and always choosing the earliest time if several are found within the desired dates.

function setAdultTickets(adultTicketsWanted) {
const adultTicketsCount = parseInt($('.quantity-control.row > input')[0].value, 10);
const ticketChangeIterations = Math.abs(adultTicketsWanted - adultTicketsCount);
const ticketChangeButton = $(.quantity-control.row > button.typcn-${adultTicketsCount < adultTicketsWanted ? 'plus' : 'minus'})[0];

for (let i = 0; i < ticketChangeIterations; i++) {
	ticketChangeButton.click();
}

}

function playSound(src) {
return new Promise((resolve) => {
const audio = new Audio(src);
audio.onended = resolve;
audio.play();
});
}

function repeatHeyListen() {
playSound('https://www.myinstants.com/media/sounds/hey_listen.mp3')
.then(repeatHeyListen);
}

function waitForAvailability() {
return new Promise((resolve) => {
setTimeout(() => {
const availableEls = $('.c-14-all.available')
if (availableEls.length === 0) {
return waitForAvailability()
.then((res) => resolve(res));
}

		resolve(availableEls);
	}, 1000);
});

}

function playSounds() {
playSound('https://www.myinstants.com/media/sounds/mlg-airhorn.mp3')
.then(() => playSound('https://www.myinstants.com/media/sounds/sound-9______.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/ps_1.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/wrong-answer-sound-effect.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/lalalalala.swf.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/tuturu_1.mp3'))
.then(() => playSound('https://www.myinstants.com/media/sounds/hallelujahshort.swf.mp3'))
.then(repeatHeyListen);
}

function addTicketsToBasket(dayElement) {
dayElement.click();

waitForAvailability()
	.then(() => {
		$('.ui-control.button.select-time')[0].click();

		setTimeout(() => {
			$('.typcn.typcn-shopping-cart.ng-binding')[0].click();
		}, 2000);
	});

}

function checkForTickets(datesWanted=[14, 15], adultTicketsWanted=2, checkFrequency=15) {
setAdultTickets(adultTicketsWanted);

function check() {
	$('.shared-calendar-button').click();

	waitForAvailability()
		.then(availableEls => {
			console.log(new Date(), 'Availability loaded. Checking for relevant dates...');
			for (let i = 0; i < availableEls.length; i++) {
				const day = parseInt(availableEls[i].innerText, 10);
				console.log('Day', day, 'is available...');
				if (datesWanted.includes(day)) {
					console.log('Found tickets!!!!!');
					playSounds();
					addTicketsToBasket(availableEls[i]);
					return;
				}
			}

			console.log(`Relevant dates not yet available. Will check again in ${checkFrequency} seconds.`);
			$('#page > div:nth-child(11) > div.modal.info-modal.w-auto-c > div > div.close').click();
			setTimeout(check, checkFrequency * 1000);
	});
};
check();

}

i just updated datesWanted.

here are the questions;

  1. when i run script, google chrome says ''undefined'' i think this is normal but i have to be sure :)
  2. after a while webpage popups an error ''SESSION WARNING
    Your session has expired.
    START OVER''

is it normal?

again sorry for disturb.
thanks for your help.

@Rovack
Copy link
Author

Rovack commented Apr 17, 2024

Hi @gokhanalpdogan! First of all, yes: getting "undefined" is normal. Just make sure after you run that, you also actually use checkForTickets, as described here, because until you do nothing is actually happening. That's also actually where you're supposed to specify the dates, although the way you did it should be fine too.

That same comment also mentions, near the bottom, how to deal with these expiring sessions, by linking here where there's a solution for that.

Hope this helps, but let me know if there are any further questions or complications.

@chfrodin
Copy link

chfrodin commented Apr 30, 2024

Hey @Rovack I just wanted to say a big thank you for this one. Got it up and running, took about five days straight use and I was able to get four tickets for next week.

@Rovack
Copy link
Author

Rovack commented May 3, 2024

@chfrodin That's awesome, makes me really happy to hear - thanks so much for letting me know! 😄

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