Use absolute times for waiting check times
This commit is contained in:
parent
363e842b56
commit
92d9f51ab1
@ -8,6 +8,17 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#resetStatus {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetStatus.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
min-width: 375px;
|
min-width: 375px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,13 @@
|
|||||||
Status: <span id="status">Inactive</span>
|
Status: <span id="status">Inactive</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="btn btn-info btn-sm" id="showConfigButton">Config</button>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm" id="resetButton">Reset</button>
|
||||||
|
<span id="resetStatus">Cleaned up!</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="bootstrap.bundle.min.js"></script>
|
<script src="bootstrap.bundle.min.js"></script>
|
||||||
<script src="popup.js"></script>
|
<script src="popup.js"></script>
|
||||||
|
|||||||
@ -9,8 +9,9 @@
|
|||||||
document.getElementById("password").value = items["__password"] || "";
|
document.getElementById("password").value = items["__password"] || "";
|
||||||
document.getElementById("frequency").value = items["__frequency"] || 1;
|
document.getElementById("frequency").value = items["__frequency"] || 1;
|
||||||
document.getElementById("status").innerText = items["__status"] || "unknown";
|
document.getElementById("status").innerText = items["__status"] || "unknown";
|
||||||
document.getElementById("currApptConsulate").innerText = items["__apptConsulate"] || "somewhere";
|
let currentAppt = items["__currentAppt"] || {"consulate": "unknown", "date": "unknown"};
|
||||||
document.getElementById("currApptDate").innerText = items["__apptDate"] || "sometime";
|
document.getElementById("currApptConsulate").innerText = currentAppt["consulate"];
|
||||||
|
document.getElementById("currApptDate").innerText = currentAppt["date"];
|
||||||
document.getElementById("deltaAppt").value = items["__deltaAppt"] || 1;
|
document.getElementById("deltaAppt").value = items["__deltaAppt"] || 1;
|
||||||
document.getElementById("deltaNow").value = items["__deltaNow"] || 1;
|
document.getElementById("deltaNow").value = items["__deltaNow"] || 1;
|
||||||
document.getElementById("autobook").checked = items["__autobook"] || false;
|
document.getElementById("autobook").checked = items["__autobook"] || false;
|
||||||
@ -80,4 +81,32 @@
|
|||||||
chrome.storage.local.set({ __deltaNow: this.value });
|
chrome.storage.local.set({ __deltaNow: this.value });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// reset button
|
||||||
|
document.getElementById("resetButton").addEventListener("click", async () => {
|
||||||
|
if (confirm("Are you sure you want to reset?")) {
|
||||||
|
await chrome.storage.local.get().then(items => {
|
||||||
|
chrome.storage.local.clear();
|
||||||
|
// keep user parameters
|
||||||
|
chrome.storage.local.set({
|
||||||
|
"__activate": items["__activate"] || false,
|
||||||
|
"__username": items["__username"] || "",
|
||||||
|
"__password": items["__password"] || "",
|
||||||
|
"__frequency": items["__frequency"] || 1,
|
||||||
|
"__deltaAppt": items["__deltaAppt"] || 1,
|
||||||
|
"__deltaNow": items["__deltaNow"] || 1,
|
||||||
|
"__autobook": items["__autobook"] || false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// show config button
|
||||||
|
document.getElementById("showConfigButton").addEventListener("click", async () => {
|
||||||
|
let config = await chrome.storage.local.get();
|
||||||
|
let configStr = JSON.stringify(config, null, 2);
|
||||||
|
let url = "data:text/plain;charset=utf-8," + encodeURIComponent(configStr);
|
||||||
|
chrome.tabs.create({ url: url });
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
const pathnameRegex = /^\/\w{2}-\w{2}\/n?iv/;
|
const pathnameRegex = /^\/\w{2}-\w{2}\/n?iv/;
|
||||||
const MAX_SIGNIN_ATTEMPTS = 1;
|
const MAX_SIGNIN_ATTEMPTS = 1;
|
||||||
const PAGE_WAIT_TIME = 3792;
|
const PAGE_WAIT_TIME = 3792;
|
||||||
const MINUTE = 67;
|
const MINUTE = 60;
|
||||||
const SOFT_BAN_COUNTDOWN = 27 * MINUTE;
|
const SOFT_BAN_TIMEOUT = 27 * MINUTE;
|
||||||
const NOTIF_CHANNEL = "snegov_test"
|
const NOTIF_CHANNEL = "snegov_test"
|
||||||
|
|
||||||
let config = {
|
let config = {
|
||||||
@ -15,8 +15,10 @@ let config = {
|
|||||||
frequency: null,
|
frequency: null,
|
||||||
countdown: null,
|
countdown: null,
|
||||||
apptId: null,
|
apptId: null,
|
||||||
apptDate: null,
|
currentAppt: {
|
||||||
apptConsulate: null,
|
consulate: null,
|
||||||
|
date: null,
|
||||||
|
},
|
||||||
signinAttempts: null,
|
signinAttempts: null,
|
||||||
consulates: null,
|
consulates: null,
|
||||||
deltaAppt: null,
|
deltaAppt: null,
|
||||||
@ -39,6 +41,17 @@ async function sendNotification(message, channel = NOTIF_CHANNEL) {
|
|||||||
.catch(e => console.error(e));
|
.catch(e => console.error(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRandomInt(max) {
|
||||||
|
return Math.floor(Math.random() * Math.floor(max));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFutureDate(minutes, maxRandomSeconds = 0) {
|
||||||
|
// return date some amount of minutes in future plus random amount of seconds
|
||||||
|
let futureDate = new Date();
|
||||||
|
futureDate.setMinutes(futureDate.getMinutes() + minutes);
|
||||||
|
futureDate.setSeconds(futureDate.getSeconds() + getRandomInt(maxRandomSeconds));
|
||||||
|
return futureDate.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
function isSignInPage() {
|
function isSignInPage() {
|
||||||
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/users\/sign_in/));
|
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/users\/sign_in/));
|
||||||
@ -107,13 +120,15 @@ async function getAppointmentId() {
|
|||||||
async function getConsulates() {
|
async function getConsulates() {
|
||||||
let consulatesSelect = document.querySelector("#appointments_consulate_appointment_facility_id")
|
let consulatesSelect = document.querySelector("#appointments_consulate_appointment_facility_id")
|
||||||
let consulatesDict = {};
|
let consulatesDict = {};
|
||||||
|
|
||||||
for (let option of consulatesSelect.options) {
|
for (let option of consulatesSelect.options) {
|
||||||
if (!option.value) continue;
|
if (!option.value) continue; // skip empty option
|
||||||
consulatesDict[option.text] = {
|
consulatesDict[option.text] = {
|
||||||
"id": parseInt(option.value),
|
"id": parseInt(option.value),
|
||||||
"isSelected": option.selected,
|
"isSelected": option.selected,
|
||||||
"bestDate": null,
|
"bestDate": null,
|
||||||
"currentDate": null,
|
"currentDate": null,
|
||||||
|
"nextCheckAt": getFutureDate(0, 60),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return consulatesDict;
|
return consulatesDict;
|
||||||
@ -129,6 +144,7 @@ async function getAvailableDates(consulateId) {
|
|||||||
return dateList;
|
return dateList;
|
||||||
})
|
})
|
||||||
.catch(e => null);
|
.catch(e => null);
|
||||||
|
// TODO catch for unauthorized
|
||||||
return dates;
|
return dates;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +164,7 @@ async function getAvailableTimes(consulateId, date) {
|
|||||||
.then(d => d.json())
|
.then(d => d.json())
|
||||||
.then(data => data.available_times)
|
.then(data => data.available_times)
|
||||||
.catch(e => null);
|
.catch(e => null);
|
||||||
|
// TODO catch for unauthorized
|
||||||
return times;
|
return times;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,8 +185,7 @@ async function runner() {
|
|||||||
config.countdown = result['__countdown'] || 0;
|
config.countdown = result['__countdown'] || 0;
|
||||||
config.signinAttempts = result['__signinAttempts'] || 0;
|
config.signinAttempts = result['__signinAttempts'] || 0;
|
||||||
config.apptId = result['__apptId'] || null;
|
config.apptId = result['__apptId'] || null;
|
||||||
config.apptDate = result['__apptDate'] || null;
|
config.currentAppt = result['__currentAppt'] || { consulate: null, date: null };
|
||||||
config.apptConsulate = result['__apptConsulate'] || null;
|
|
||||||
config.consulates = result['__consulates'] || null;
|
config.consulates = result['__consulates'] || null;
|
||||||
config.deltaAppt = result['__deltaAppt'] || 1;
|
config.deltaAppt = result['__deltaAppt'] || 1;
|
||||||
config.deltaNow = result['__deltaNow'] || 1;
|
config.deltaNow = result['__deltaNow'] || 1;
|
||||||
@ -184,14 +200,21 @@ async function runner() {
|
|||||||
for (let key in config) {
|
for (let key in config) {
|
||||||
if (config.hasOwnProperty(key)
|
if (config.hasOwnProperty(key)
|
||||||
&& !_.isEqual(config[key], prev_config[key])) {
|
&& !_.isEqual(config[key], prev_config[key])) {
|
||||||
console.log(`Config change: ${key}, ${prev_config[key]} => ${config[key]}`);
|
console.log(`Config change: ${key}, ${JSON.stringify(prev_config[key])} => ${JSON.stringify(config[key])}`);
|
||||||
|
|
||||||
// reduce countdown if frequency is reduced
|
// reduce wait times for consulates if frequency is increased
|
||||||
if (key === 'frequency') {
|
if (key === 'frequency') {
|
||||||
let max_countdown = config[key] * MINUTE;
|
let wasChanged = false;
|
||||||
if (config.countdown > max_countdown) {
|
for (let consulate in config.consulates) {
|
||||||
config.countdown = max_countdown;
|
let newNextCheckAt = getFutureDate(config.frequency, 10);
|
||||||
await chrome.storage.local.set({ "__countdown": config.countdown });
|
if (config.consulates[consulate].nextCheckAt > newNextCheckAt) {
|
||||||
|
config.consulates[consulate].nextCheckAt = newNextCheckAt;
|
||||||
|
wasChanged = true;
|
||||||
|
console.log(`Reducing wait time for ${consulate} from ${config.consulates[consulate].nextCheckAt} to ${newNextCheckAt}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wasChanged) {
|
||||||
|
await chrome.storage.local.set({ "__consulates": config.consulates });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,23 +346,25 @@ async function runner() {
|
|||||||
let apptDate = new Date(apptInfo.match(/\d{1,2} \w+, \d{4}/)[0]);
|
let apptDate = new Date(apptInfo.match(/\d{1,2} \w+, \d{4}/)[0]);
|
||||||
apptDate = apptDate.toISOString().slice(0, 10);
|
apptDate = apptDate.toISOString().slice(0, 10);
|
||||||
if (apptDate && apptConsulate
|
if (apptDate && apptConsulate
|
||||||
&& (apptDate != config.apptDate || apptConsulate != config.apptConsulate)) {
|
&& (apptDate != config.currentAppt.date
|
||||||
console.log(`New appointment date: ${apptDate} at ${apptConsulate}, old: ${config.apptDate} at ${config.apptConsulate}`);
|
|| apptConsulate != config.currentAppt.consulate)) {
|
||||||
config.apptDate = apptDate;
|
console.log(`New appointment date: ${apptDate} at ${apptConsulate},
|
||||||
config.apptConsulate = apptConsulate;
|
old: ${config.currentAppt.consulate} at ${config.currentAppt.date}`);
|
||||||
await chrome.storage.local.set({ "__apptDate": apptDate });
|
config.currentAppt.date = apptDate;
|
||||||
await chrome.storage.local.set({ "__apptConsulate": apptConsulate });
|
config.currentAppt.consulate = apptConsulate;
|
||||||
|
await chrome.storage.local.set({ "__currentAppt": config.currentAppt });
|
||||||
}
|
}
|
||||||
|
|
||||||
// go to appointment page
|
// go to appointment page
|
||||||
let apptLink = apptInfoCard.querySelector("p.consular-appt [href]").getAttribute("href").replace("/addresses/consulate", "/appointment");
|
let apptLink = apptInfoCard.querySelector("p.consular-appt [href]")
|
||||||
|
.getAttribute("href").replace("/addresses/consulate", "/appointment");
|
||||||
window.location.href = apptLink;
|
window.location.href = apptLink;
|
||||||
await delay(PAGE_WAIT_TIME);
|
await delay(PAGE_WAIT_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isAppointmentPage()) {
|
else if (isAppointmentPage()) {
|
||||||
// if no apptDate, fetch it from dashboard page
|
// if no apptDate, fetch it from dashboard page
|
||||||
if (!config.apptDate) {
|
if (!config.currentAppt.date) {
|
||||||
console.log('No appointment date is set, going back to dashboard');
|
console.log('No appointment date is set, going back to dashboard');
|
||||||
window.location = window.location.pathname.replace(/schedule.*/g, "/account");
|
window.location = window.location.pathname.replace(/schedule.*/g, "/account");
|
||||||
await delay(PAGE_WAIT_TIME);
|
await delay(PAGE_WAIT_TIME);
|
||||||
@ -389,28 +414,30 @@ async function runner() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let consulate of selectedConsulates) {
|
for (let consulate of selectedConsulates) {
|
||||||
|
// skip if not time to check
|
||||||
|
if (config.consulates[consulate].nextCheckAt > new Date().toISOString()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Checking dates for ' + consulate);
|
console.log('Checking dates for ' + consulate);
|
||||||
let availDates = await getAvailableDates(config.consulates[consulate].id);
|
let availDates = await getAvailableDates(config.consulates[consulate].id);
|
||||||
config.countdown = config.frequency * MINUTE;
|
config.consulates[consulate].nextCheckAt = getFutureDate(config.frequency, 10);
|
||||||
await chrome.storage.local.set({ "__countdown": config.countdown });
|
|
||||||
|
|
||||||
if (!availDates) {
|
if (!availDates) {
|
||||||
msg = `Failed to fetch available dates in ${consulate}`;
|
msg = `Failed to fetch available dates in ${consulate}`;
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
await chrome.storage.local.set({ "__status": msg });
|
await chrome.storage.local.set({ "__status": msg });
|
||||||
isRunning = false;
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if empty list, either we're banned or non operational hours or dead consulate
|
// if empty list, either we're banned or non operational hours or dead consulate
|
||||||
|
// wait for some time before checking again
|
||||||
if (availDates.length == 0) {
|
if (availDates.length == 0) {
|
||||||
msg = `No available dates in ${consulate}, probably banned`;
|
msg = `No available dates in ${consulate}, probably banned`;
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
await chrome.storage.local.set({ "__status": msg });
|
await chrome.storage.local.set({ "__status": msg });
|
||||||
config.countdown = SOFT_BAN_COUNTDOWN;
|
config.consulates[consulate].nextCheckAt = getFutureDate(SOFT_BAN_TIMEOUT, 10);
|
||||||
await chrome.storage.local.set({ "__countdown": config.countdown });
|
continue;
|
||||||
isRunning = false;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Available dates for ${consulate}: ${availDates}`);
|
console.log(`Available dates for ${consulate}: ${availDates}`);
|
||||||
@ -420,16 +447,14 @@ async function runner() {
|
|||||||
console.log(`New record for ${consulate}: ${availDates[0]}`);
|
console.log(`New record for ${consulate}: ${availDates[0]}`);
|
||||||
config.consulates[consulate].bestDate = availDates[0];
|
config.consulates[consulate].bestDate = availDates[0];
|
||||||
}
|
}
|
||||||
await chrome.storage.local.set({ "__consulates": config.consulates });
|
|
||||||
|
|
||||||
// filter dates with our requests
|
// filter dates with our requests
|
||||||
let filteredDates = await filterDates(availDates, config.apptDate, config.deltaAppt, config.deltaNow);
|
let filteredDates = await filterDates(availDates, config.currentAppt.date, config.deltaAppt, config.deltaNow);
|
||||||
if (!filteredDates.length) {
|
if (!filteredDates.length) {
|
||||||
msg = `No better dates in ${consulate}, currently available ${availDates[0]}`;
|
msg = `No better dates in ${consulate}, currently available ${availDates[0]}`;
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
await chrome.storage.local.set({ "__status": msg});
|
await chrome.storage.local.set({ "__status": msg});
|
||||||
isRunning = false;
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Dates worth rescheduling in ${consulate}: ${filteredDates}`);
|
console.log(`Dates worth rescheduling in ${consulate}: ${filteredDates}`);
|
||||||
@ -446,15 +471,13 @@ async function runner() {
|
|||||||
msg = `Failed to fetch available timeslots in ${consulate} at ${chosenDate}`;
|
msg = `Failed to fetch available timeslots in ${consulate} at ${chosenDate}`;
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
await chrome.storage.local.set({ "__status": msg});
|
await chrome.storage.local.set({ "__status": msg});
|
||||||
isRunning = false;
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (availTimes.length == 0) {
|
if (availTimes.length == 0) {
|
||||||
msg = `No timeslots in ${consulate} at ${chosenDate}`;
|
msg = `No timeslots in ${consulate} at ${chosenDate}`;
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
await chrome.storage.local.set({ "__status": msg});
|
await chrome.storage.local.set({ "__status": msg});
|
||||||
isRunning = false;
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
console.log(`Available timeslots in ${consulate} at ${chosenDate}: ${availTimes}`);
|
console.log(`Available timeslots in ${consulate} at ${chosenDate}: ${availTimes}`);
|
||||||
let chosenTime = availTimes[0];
|
let chosenTime = availTimes[0];
|
||||||
@ -481,15 +504,21 @@ async function runner() {
|
|||||||
}
|
}
|
||||||
} // end consulates loop
|
} // end consulates loop
|
||||||
|
|
||||||
|
for (let consulate in config.consulates) {
|
||||||
|
if (config.consulates[consulate].nextCheckAt != prev_config.consulates[consulate].nextCheckAt) {
|
||||||
|
console.log(`Next check for ${consulate} at ${config.consulates[consulate].nextCheckAt}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await chrome.storage.local.set({ "__consulates": config.consulates });
|
||||||
|
isRunning = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isConfirmationPage) {
|
else if (isConfirmationPage) {
|
||||||
// go back to schedule after successful reschedule
|
// go back to schedule after successful reschedule
|
||||||
await delay(PAGE_WAIT_TIME);
|
await delay(PAGE_WAIT_TIME);
|
||||||
config.apptDate = null;
|
config.currentAppt = { consulate: null, date: null};
|
||||||
await chrome.storage.local.set({"__apptDate": config.apptDate});
|
await chrome.storage.local.set({"__currentAppt": config.currentAppt});
|
||||||
config.apptConsulate = null;
|
|
||||||
await chrome.storage.local.set({"__apptConsulate": config.apptConsulate});
|
|
||||||
console.log('Rescheduled successfully');
|
console.log('Rescheduled successfully');
|
||||||
window.location = window.location.pathname.replace(/schedule.*/g, "");
|
window.location = window.location.pathname.replace(/schedule.*/g, "");
|
||||||
await delay(PAGE_WAIT_TIME);
|
await delay(PAGE_WAIT_TIME);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user