-
-
Save Rovack/51e0fb558ee0fa4ce0e2cd5f0ab17cb1 to your computer and use it in GitHub Desktop.
// 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(); | |
} |
Well, the site is still very slow for me, so I can't fully test the new version, but I have tried it once or twice and it seemed to work well enough.
So, perhaps you'd like to give it a shot, even though it's still experimental at this point and could definitely have issues.
If so, just copy the code below (instead of the original script at the top of this page), and then run:
checkForTicketsInMonth([13, 14, 15, 16], 2)
.
(Of course, don't forget to also add the //
mentioned in Oct 15th and manually select the ticket amounts before running the script, since you want both adult and child tickets.)
The code is as follows:
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(monthWanted) {
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(monthWanted)
.then((res) => resolve(res));
}
if (monthWanted == null) {
resolve({ availableEls });
return;
}
const monthValue = $('[name="ctl00$ContentPlaceHolder$SalesChannelDetailControl$EventsDateTimeSelectorModal$EventsDateTimeSelector$CalendarSelector$MonthDropDownList"]')[0].value;
const month = parseInt(monthValue.replace(/^\D+/g, ''), 10);
if (month < monthWanted) {
console.log(`Month too early (${month}) - skipping to next month.`);
$('[name="ctl00$ContentPlaceHolder$SalesChannelDetailControl$EventsDateTimeSelectorModal$EventsDateTimeSelector$CalendarSelector$NextMonthImageButton"]').click();
return waitForAvailability(monthWanted).then(res => resolve(res));
}
resolve({ availableEls, month });
}, 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, monthWanted) {
setAdultTickets(adultTicketsWanted);
function check() {
$('.shared-calendar-button').click();
waitForAvailability(monthWanted)
.then(({ availableEls, month }) => {
console.log(new Date(), `Availability loaded${month != null ? ` for month ${month}` : ''}. Checking for relevant dates...`);
if (monthWanted != null && month > monthWanted) {
console.log(`Month is too late (${month}). Will check again in ${checkFrequency} seconds.`);
setTimeout(check, checkFrequency * 1000);
return;
}
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();
}
function checkForTicketsInMonth(datesWanted, monthWanted, adultTicketsWanted, checkFrequency) {
return checkForTickets(datesWanted, adultTicketsWanted, checkFrequency, monthWanted);
}
Ah, just saw your reply @mihaela2020. To answer your question: Yes, using a month that you know does have availability is the best way to test, just as you said.
Using the new version of the script, that would mean running e.g.: checkForTicketsInMonth([13, 14, 15, 16], 3)
, instead of checkForTicketsInMonth([13, 14, 15, 16], 2)
, just to test.
Also, note that I've updated my earlier comment a bit, and also added a new one with a version of the script that should handle more cases, even though it isn't as well-tested as the original version (just forgot to tag you on that one).
Finally, looking at the site right now, it seems Feb 14-16 all have availability, so you might be able to just manually book the tickets you want. That is, if you go in right now, the script might not even be necessary. :)
(Edit: I find it interesting that the site was extremely slow for me for the last hour or so, then 5-10 minutes ago a ton of availability opened up in January and February, then it seems that availability disappeared in just a couple of minutes, and now the site is more or less back to its normal speed. I wonder if some process involving availability was going on that was slowing down the site... if so, that would suggest it's worth keeping an eye on the site around 8-9 AM GMT, which does match advice I've seen mentioned on TripAdvisor before.)
Great, glad to hear the script works @mihaela2020. :)
Just note that if tickets open up for January and February at the same time, as was the case this morning, the original version probably won't work (it only knows how to keep waiting when availability is too late, but doesn't handle availability that's too early, meaning it could keep looking at Jan instead of Feb).
For that, the new version is preferable, since it also knows to go to the next month (if you want, you could test that by looking for tickets in April, e.g. checkForTicketsInMonth([13, 14, 15, 16], 4)
).
I have a problem with the new version:
Although I'm interested in February and at the end I run checkForTicketsInMonth ([13, โโ14, 15, 16], 2)
it puts in my basket tickets for March.
It doesn't wait for February availability.
You're absolutely right, @mihaela2020. I just updated the code in the comment with a fix.
And, now that the site is back to full speed, I was able to test all cases: a month that's too late, too early, and just right.
All seem to work now, as far as I can tell.
Hello again!
Your method works very well. Thanks!
I have family tickets in my basket but I don't know for what date or time.
Do you know how I can find out?
Oh wow, that's a very good question @mihaela2020. Personally I've never tried getting Family tickets, so I never even realized they don't show the dates in the basket. For Adult or Child tickets, it shows up in the basket as e.g. "Adult- 03/03/2020 10:00" or "Child- 03/03/2020 15:00".
Really weird choice for the website design...
It's likely that if the script was given the right parameters, and automatically put tickets into the basket, the tickets will be somewhere in the specified range. Even with the new version, that's not as well-tested, I'd say I have 80% confidence in that.
So, one strategy would be to just buy the tickets, and if it then turns out that they were somehow wrong, cancel them. According to their Terms and Conditions, you should be able to cancel by phone within 7 days of purchasing, if you're a resident of the EU.
If you're not, I have no idea how amenable they are to refunding tickets.
If that's not an option, it might be possible to make some modifications to the script to make it store somewhere which dates it selected, though off the top of my head I'm not sure what would be the best way to do that. The problem is that when the page changes as part of going to the basket, the log of messages is unfortunately cleared. So, it'd require some actual storage option...
Actually, one very simple solution would be just removing the part that automatically adds the tickets to the basket. If you're relatively near the computer for enough of the time, you could rely on the loud sounds to alert you once tickets become available, and then come put them in the basket yourself.
For that, I believe all you'd need to do is change the line that's currently:
addTicketsToBasket(availableEls[i]);
into:
// addTicketsToBasket(availableEls[i]);
Anyway, any option that requires modifications to the script would of course require disposing of the tickets you currently have, and running the script again. Not the end of the world, since there's still enough time ahead of your visit that it would likely find new tickets in a day or 2, but still somewhat of a risk.
I searched in the "View Page Source" of the basket for 2020 and found the date and time 14/02/2020 11:00.
๐
Ah, of course! Excellent idea. :)
For future reference, in case anyone else encounters this issue, you should be able to see the date and time by typing the following in the Console:
$('[ng-if="packageItem.packageEventDate"] > .selected-date')[0].innerHTML
So glad to hear you got tickets @mihaela2020. Have a great time!
P.S. I've now also updated the Caveats in the top comment to reflect this problem and your solution, so others may benefit from your experience. :)
So happy to hear that, @Capybara218!
Thanks for letting me know, and I hope you and your SO have an amazing time there! :)
Nowadays after some time you get a notification about expiring session and have to click Extend session
button.
Here is updated script - at the beginning of check()
method we click extend session button if its available, like so:
if ($('.ui-control.button.extendSession').length != 0) {
console.log('Extending session');
$('.ui-control.button.extendSession').click();
}
Full script:
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(monthWanted) {
return new Promise((resolve) => {
setTimeout(() => {
const availableEls = $('.c-14-all.available'), isLoading = $('.calendar-modal[data-component=eventTimeModal] .modal-content > .loading-container.hide').length === 0;
if (isLoading) {
return waitForAvailability(monthWanted)
.then((res) => resolve(res));
}
if (monthWanted == null) {
resolve({ availableEls });
}
const monthValue = $('[name="ctl00$ContentPlaceHolder$SalesChannelDetailControl$EventsDateTimeSelectorModal$EventsDateTimeSelector$CalendarSelector$MonthDropDownList"]')[0].value;
const month = parseInt(monthValue.replace(/^\D+/g, ''), 10);
if (month < monthWanted) {
console.log(`Month too early (${month}) - skipping to next month.`);
$('[name="ctl00$ContentPlaceHolder$SalesChannelDetailControl$EventsDateTimeSelectorModal$EventsDateTimeSelector$CalendarSelector$NextMonthImageButton"]').click();
return waitForAvailability(monthWanted).then(res => resolve(res));
}
resolve({ availableEls, month });
}, 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, monthWanted) {
setAdultTickets(adultTicketsWanted);
function check() {
if ($('.ui-control.button.extendSession').length != 0) {
console.log('Extending session');
$('.ui-control.button.extendSession').click();
}
$('.shared-calendar-button').click();
waitForAvailability(monthWanted)
.then(({ availableEls, month }) => {
console.log(new Date(), `Availability loaded${month != null ? ` for month ${month}` : ''}. Checking for relevant dates...`);
if (monthWanted != null && month > monthWanted) {
console.log(`Month is too late (${month}). Will check again in ${checkFrequency} seconds.`);
setTimeout(check, checkFrequency * 1000);
return;
}
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.`);
setTimeout(check, checkFrequency * 1000);
});
};
check();
}
function checkForTicketsInMonth(datesWanted, monthWanted, adultTicketsWanted, checkFrequency) {
return checkForTickets(datesWanted, adultTicketsWanted, checkFrequency, monthWanted);
}
Oh that's great to know, thanks for the fix @Flame239! Added it to the instructions.
The script is really cool. Nice work on it, @Rovack . I have been running it for a day now and this morning for the first time, it found a hit on one of my days, but with "Insufficient Quantities" of tickets available. When that happens there's no way to stop the mp3 from playing even though it can't add the available time to the basket. Since I'm looking for the "Family (2 adults + 2 children)" and 1 extra Child ticket, I commented out "setAdultTickets(adultTicketsWanted);" and selected my quantities manually from the site. Is there a way I could change the script to look specifically for what I need so it wouldn't celebrate unless all my needed tickets were found?
Hey @Silverleaf42, really sorry for the late response. Have you gotten it to work yet?
If not (though I hope you have), I must admit it's my first time hearing about this "Insufficient Quantities" case. I'd have thought if you specify multiple types of tickets, the site would only show you times where they're all available at once. I guess for some reason, in certain cases they prefer to show dates/times that aren't really available.
To address this in the script would take a few changes, to both addTicketsToBasket
and check
. Here's a version that seems to work:
[...]
async function addTicketsToBasket(dayElement) {
dayElement.click();
await new Promise((resolve) => setTimeout(resolve, 2000));
await waitForAvailability();
const chooseTimeButton = $('.ui-control.button.select-time:not(.disabled)')[0];
if (!chooseTimeButton) return false;
console.log('Found tickets!!!!!');
playSounds();
chooseTimeButton.click();
await new Promise((resolve) => setTimeout(resolve, 2000));
$('.typcn.typcn-shopping-cart.ng-binding')[0].click();
return true;
}
function checkForTickets(datesWanted=[6, 7, 8], adultTicketsWanted=2, checkFrequency=15, monthWanted) {
setAdultTickets(adultTicketsWanted);
async function check() {
if ($('.ui-control.button.extendSession').length != 0) {
console.log('Extending session');
$('.ui-control.button.extendSession').click();
}
$('.shared-calendar-button').click();
waitForAvailability(monthWanted)
.then(async ({ availableEls, month }) => {
console.log(new Date(), `Availability loaded${month != null ? ` for month ${month}` : ''}. Checking for relevant dates...`);
if (monthWanted != null && month > monthWanted) {
console.log(`Month is too late (${month}). Will check again in ${checkFrequency} seconds.`);
setTimeout(check, checkFrequency * 1000);
return;
}
for (let i = 0; i < availableEls.length; i++) {
const day = parseInt($('.calendar>.row:not(.blankLoader) .calendar-body .day.available')[i].innerText, 10);
console.log('Day', day, 'is available...');
if (datesWanted.includes(day)) {
const succeeded = await addTicketsToBasket($('.calendar>.row:not(.blankLoader) .calendar-body .day.available')[i]);
if (succeeded) return;
}
}
console.log(`Relevant dates not yet available. Will check again in ${checkFrequency} seconds.`);
setTimeout(check, checkFrequency * 1000);
});
};
check();
}
[...]
(There may be a very slight race condition here, where if there are multiple relevant dates but the first turn(s) out to have insufficient quantity, in theory availability could change before we attempt the next date and the script wouldn't necessarily handle that. But I think it's fairly unlikely, not too harmful if it does happen, and I can't think of a very easy solution since we have to re-fetch $('.calendar>.row:not(.blankLoader) .calendar-body .day.available')
after each time a date is clicked, so hopefully it won't be a problem.)
On a separate note, if anyone in the future does also want the script to automatically choose the quantities with multiple types of tickets (though IMO just doing it manually is probably easiest), you could just make the following modifications:
Replace setAdultTickets
with:
function setTickets(ticketsWanted, categoryLineNumber = 0) {
const ticketsCount = parseInt($('.quantity-control.row > input')[categoryLineNumber].value, 10);
const ticketChangeIterations = Math.abs(ticketsWanted - ticketsCount);
const ticketChangeButton = $(`.quantity-control.row > button.typcn-${ticketsCount < ticketsWanted ? 'plus' : 'minus'}`)[categoryLineNumber];
for (let i = 0; i < ticketChangeIterations; i++) {
ticketChangeButton.click();
}
}
And in the first line of checkForTickets
, replace setAdultTickets(adultTicketsWanted);
with e.g.:
setTickets(1, 3); // 1 x "Family (2 Adults + 2 Children)" ticket
setTickets(1, 1); // 1 x "Child" ticket
As you can probably tell, the 2nd parameter is the line number of the type of ticket you want, starting from 0 (so e.g. 0 for "Adult", 1 for "Child", 2 for "4 and Under", and so on), and the 1st parameter is how many of that type of ticket you want.
Hope this helps!
setTickets(1, 3); // 1 x "Family (2 Adults + 2 Children)" ticket
setTickets(1, 1); // 1 x "Child" ticket
Thanks @Rovack! I haven't gotten them yet, but I'm trying the changes you suggested now to see if it works and I'll let you know.
BTW, I ran the script all day yesterday and not a thing popped up. Ran it again early this morning (starting at 6:15am ET) and got our tickets within 15 minutes. Thanks again, @Rovack
Yay, that's great news @Silverleaf42!! Thanks for letting me know it worked.
Hope you have a great time there! ๐
Hello!
First of all, I want to show my gratitude and say thank you SO much for sharing this with everyone and helping people out even to this day :) :)
I managed to get the script running which is great, but I'd like to check a couple of things if you don't mind. Sometimes I see "Insufficient quantities" though as far as I can tell, I've only specified one type of ticket (family). I've attached the code I'm using. Am I maybe doing something wrong there?
Not a big deal, though after some time I see a timeout. Again, not sure if I've missed something or am doing something incorrectly.
Thank you in advance and I hope you're having a great day!
function setAdultTickets(adultTicketsWanted) { const adultTicketsCount = parseInt($('.quantity-control.row > input')[3].value, 10); const ticketChangeIterations = Math.abs(adultTicketsWanted - adultTicketsCount); const ticketChangeButton = $(
.quantity-control.row > button.typcn-${adultTicketsCount < adultTicketsWanted ? 'plus' : 'minus'}`)[3];
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(monthWanted) {
return new Promise((resolve) => {
setTimeout(() => {
const availableEls =
if (isLoading) {
return waitForAvailability(monthWanted)
.then((res) => resolve(res));
}
if (monthWanted == null) {
resolve({ availableEls });
}
const monthValue = $('[name="ctl00$ContentPlaceHolder$SalesChannelDetailControl$EventsDateTimeSelectorModal$EventsDateTimeSelector$CalendarSelector$MonthDropDownList"]')[0].value;
const month = parseInt(monthValue.replace(/^\D+/g, ''), 10);
if (month < monthWanted) {
console.log(`Month too early (${month}) - skipping to next month.`);
$('[name="ctl00$ContentPlaceHolder$SalesChannelDetailControl$EventsDateTimeSelectorModal$EventsDateTimeSelector$CalendarSelector$NextMonthImageButton"]').click();
return waitForAvailability(monthWanted).then(res => resolve(res));
}
resolve({ availableEls, month });
}, 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=1, checkFrequency=10, monthWanted) {
setAdultTickets(adultTicketsWanted);
function check() {
if ($('.ui-control.button.extendSession').length != 0) {
console.log('Extending session');
$('.ui-control.button.extendSession').click();
}
$('.shared-calendar-button').click();
waitForAvailability(monthWanted)
.then(({ availableEls, month }) => {
console.log(new Date(), `Availability loaded${month != null ? ` for month ${month}` : ''}. Checking for relevant dates...`);
if (monthWanted != null && month > monthWanted) {
console.log(`Month is too late (${month}). Will check again in ${checkFrequency} seconds.`);
setTimeout(check, checkFrequency * 1000);
return;
}
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();
}
function checkForTicketsInMonth(datesWanted, monthWanted, adultTicketsWanted, checkFrequency) {
return checkForTickets(datesWanted, adultTicketsWanted, checkFrequency, monthWanted);
}`
Hey @sjezewska. :) For the "Insufficient quantities" case, it's even weirder that it can happen with just 1 type of ticket, but I guess it's just a thing the system does now. Anyway, the changes specified here, to addTicketsToBasket
and check
, should address that.
As for the timeout, I never saw it myself, but could it be the same "Extend session" issue Flame239 mentioned here?
If so, you could try the fix they suggested.
Let me know if either of these problems persists even with these changes, and I can look more deeply into it.
@Rovack sorry for the late reply and thanks for getting back to me. I kept seeing "Insufficient quantities" from time to time and I think the timeout issue was because of my internet connection sigh. I ended up getting tickets though, so REALLY happy! Thank you again :)
Great to hear it, @sjezewska! Hope you have a wonderful time. :)
Hi Rovack! Thanks for the script, I'm looking for tickets this October and the script is working great. However since the 2024 tickets have been released now the script skips through until October '24, which of course it can find availability for and adds them to the basket, thus stopping the loop.
I'm sure there is a way to specify the year, so that the script will keep looking for tickets in October '23 - I'm just not savvy enough to know how to find the correct syntax for this. Can you please help to add this in?
Hi @amandaoliver15. This is actually a really interesting case - normally the version that picks a specific month shouldn't run into this problem, because it would just stop once it gets to a month that's later than the requested one. Except currently the closest availability is actually in January 2024, and since the script doesn't look at the year, it just figures January is earlier than October, and progresses through the months.
To fix this, you should be able to just add the following lines:
const yearValue = $('[ng-model="viewModel.calendar.year"]')[0].value;
const year = parseInt(yearValue.replace(/^\D+/g, ''), 10);
const currentYear = new Date().getFullYear();
if (year > currentYear) {
console.log(`Year too late (${year}) - stopping.`);
return resolve({ availableEls, month: month + 12 * (year - currentYear) });
}
They go right before the code that checks the month, i.e. before:
if (month < monthWanted) {
but after:
const month = parseInt(monthValue.replace(/^\D+/g, ''), 10);
(There might be slightly cleaner/more general ways to handle year selection, but for the current situation at least this should work.)
Once you try it out, if it there are any problems or questions or anything else, just let me know. :)
Hi Rovack, script works perfectly, now it's a waiting game. Thanks again for the amazing work, and quick response ๐
Update: Managed to get some tickets after about an hour! Thanks again!
Thank you so much to Rovack and everybody who commented!
I've managed to find the tickets I needed at the busiest time of the year.
It took me four days of continuous running...
Thanks again!!
So glad to hear it, @gneotel. ๐ Hope you have a great time!!
Hi @Rovack, first big thanks for what you did here! the script is amazing. I hope I will manage to find a 2 free slot in December.
I do also have one question. Sometimes I am getting in console:
angular.js:16410 TypeError: Cannot read properties of undefined (reading 'value') at WBUK-core.min.js?v=wbuk_7.8.0.21.1-13-g1fac657e7b:6:15250 at Object.r [as forEach] (angular.js:487:20) at e.getTimes (WBUK-core.min.js?v=wbuk_7.8.0.21.1-13-g1fac657e7b:6:15125) at e.getTimes (WBUK-core.min.js?v=wbuk_7.8.0.21.1-13-g1fac657e7b:2:11130) at e.parse (WBUK-core.min.js?v=wbuk_7.8.0.21.1-13-g1fac657e7b:6:14771) at e.parse (WBUK-core.min.js?v=wbuk_7.8.0.21.1-13-g1fac657e7b:2:11130) at e.<anonymous> (WBUK-core.min.js?v=wbuk_7.8.0.21.1-13-g1fac657e7b:14:18472) at angular.js:1506:3 at angular.js:18242:20 at m.$digest (angular.js:19366:15) 'Possibly unhandled rejection: {}'
and on the screen I see calendar popup but without calendar inside. (it seems that this part was not loaded)
Did you experience something similar?
EDIT:
It's probably happen when there is no free slots in the entire month, like:
Hi @mihaela2020. That could be because a couple months ago the site made a certain change, that required a slight tweak to the Oct 15 code for finding tickets in a specific month. I've now added an Edit at the bottom of the Oct 15 comment, with what should be a fixed version of the code.
Once you use the updated fix (and assuming you put the number '2' in the check instead of '10', since you want February), that message should only appear when there really isn't any availability earlier than March.
Of course, in that case, if the message does appear and you see that the month being shown in the pop-up is indeed later than February, that's perfectly fine: as the message says, it'll just try again in 15 seconds, and will keep trying until it finds availability on the given dates in February.
The only remaining issue would be the case where January still has availability, in which case February won't even be checked.
I'm planning on adding a new version of the script that will handle that case as well, but right now the site is so incredibly slow for me that I can't really test any changes. Hopefully I'll be able to get it working shortly.
Anyway, let me know if this works, or if there's any more questions/issues/clarifications/anything I can help with. And good luck!