Compare commits

...

8 Commits

2 changed files with 59 additions and 27 deletions

View File

@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "not-a-rescheduler", "name": "not-a-rescheduler",
"version": "0.0.8", "version": "0.0.10",
"permissions": [ "storage", "tabs", "activeTab", "notifications", "declarativeContent" ], "permissions": [ "storage", "tabs", "activeTab", "notifications", "declarativeContent" ],
"content_scripts": [ "content_scripts": [
{ {

View File

@ -5,9 +5,12 @@ const pathnameRegex = /^\/\w{2}-\w{2}\/n?iv/;
const MAX_SIGNIN_ATTEMPTS = 3; const MAX_SIGNIN_ATTEMPTS = 3;
const PAGE_WAIT_TIME = 3792; const PAGE_WAIT_TIME = 3792;
const MINUTE = 60; const MINUTE = 60;
const RANDOM_JITTER = 0.1; const RND_VAR_COEFF = 0.1;
const SOFT_BAN_TIMEOUT = 27; const SOFT_BAN_TIMEOUT = 27;
const NOTIF_CHANNEL = "snegov_test" const NOTIF_CHANNEL = "snegov";
const CHECK_OPER_HOURS = true;
const OPER_HOURS_START = 23;
const OPER_HOURS_END = 9;
let cfg = { let cfg = {
activate: undefined, activate: undefined,
@ -50,18 +53,22 @@ function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max)); return Math.floor(Math.random() * Math.floor(max));
} }
function getFutureDate(minutes, frequency) {
function getJitter(frequency) {
return frequency * MINUTE * RANDOM_JITTER;
}
function getFutureDate(minutes, maxRandomSeconds = 0) {
// return date some amount of minutes in future plus random amount of seconds // return date some amount of minutes in future plus random amount of seconds
let futureDate = new Date(); let futureDate = new Date();
futureDate.setSeconds(futureDate.getSeconds() + minutes * MINUTE + getRandomInt(maxRandomSeconds)); const randomVariation = frequency * MINUTE * RND_VAR_COEFF;
const randomSign = Math.random() < 0.5 ? -1 : 1;
const offset = randomSign * getRandomInt(randomVariation);
futureDate.setSeconds(futureDate.getSeconds() + minutes * MINUTE + offset);
return futureDate.toISOString(); return futureDate.toISOString();
} }
function isNoBanTime(frequency = 5) {
let now = new Date();
return (now.getHours() === OPER_HOURS_START && now.getMinutes() < frequency);
}
function hiddenPassword(cfg) { function hiddenPassword(cfg) {
return { return {
...cfg, ...cfg,
@ -106,7 +113,7 @@ function ensureRequiredConsulateProperties(consCtx, consCfg, frequency = 1) {
"id": consCtx[c]?.id || null, "id": consCtx[c]?.id || null,
"bestDate": consCtx[c]?.bestDate || null, "bestDate": consCtx[c]?.bestDate || null,
"currentDate": consCtx[c]?.currentDate || null, "currentDate": consCtx[c]?.currentDate || null,
"nextCheckAt": consCtx[c]?.nextCheckAt || getFutureDate(0, frequency * MINUTE), "nextCheckAt": consCtx[c]?.nextCheckAt || getFutureDate(0, frequency),
}; };
} }
if (!consCfg[c] || !hasAllKeys(consCfg[c], reqCfgKeys)) { if (!consCfg[c] || !hasAllKeys(consCfg[c], reqCfgKeys)) {
@ -244,7 +251,7 @@ async function getAvailableDates(consulateId) {
if (!response.ok) { if (!response.ok) {
if (response.status === 401) { if (response.status === 401) {
await sendNotification('Logged out due to 401 error'); console.log('Logged out due to 401 error');
await logOut(); await logOut();
} }
const body = await response.text(); const body = await response.text();
@ -332,7 +339,7 @@ async function runner() {
if (key === 'frequency') { if (key === 'frequency') {
let wasChanged = false; let wasChanged = false;
for (let c in ctx.consulates) { for (let c in ctx.consulates) {
let newNextCheckAt = getFutureDate(cfg.frequency, getJitter(cfg.frequency)); let newNextCheckAt = getFutureDate(cfg.frequency, cfg.frequency);
if (ctx.consulates[c].nextCheckAt > newNextCheckAt) { if (ctx.consulates[c].nextCheckAt > newNextCheckAt) {
console.log(`Reducing wait time for ${c} from ${ctx.consulates[c].nextCheckAt} to ${newNextCheckAt}`); console.log(`Reducing wait time for ${c} from ${ctx.consulates[c].nextCheckAt} to ${newNextCheckAt}`);
ctx.consulates[c].nextCheckAt = newNextCheckAt; ctx.consulates[c].nextCheckAt = newNextCheckAt;
@ -382,6 +389,19 @@ async function runner() {
return; return;
} }
if (CHECK_OPER_HOURS) {
// Check if current time is between 11pm and 9am UTC (4pm - 2am PST)
let now = new Date();
let currentHourUTC = now.getUTCHours();
if (currentHourUTC >= OPER_HOURS_START || currentHourUTC < OPER_HOURS_END) {
// Continue running the code
} else {
await chrome.storage.local.set({ "ctx_statusMsg": "not operational hours" });
isRunning = false;
return;
}
}
if (isFoundAppointment) { if (isFoundAppointment) {
// don't do anything if appointment is found and manual booking is required // don't do anything if appointment is found and manual booking is required
if (isAppointmentPage()) { if (isAppointmentPage()) {
@ -481,8 +501,12 @@ async function runner() {
} }
if (apptDate != ctx.currentAppt.date || apptConsulate != ctx.currentAppt.consulate) { if (apptDate != ctx.currentAppt.date || apptConsulate != ctx.currentAppt.consulate) {
console.log(`New appointment date: ${apptDate} at ${apptConsulate}, msg = `New appointment date: ${apptDate} at ${apptConsulate}`
old: ${ctx.currentAppt.consulate} at ${ctx.currentAppt.date}`); if (ctx.currentAppt.date != null) {
sendNotification(msg);
}
msg += `, was: ${ctx.currentAppt.consulate} at ${ctx.currentAppt.date}`
console.log(msg);
ctx.currentAppt = { consulate: apptConsulate, date: apptDate }; ctx.currentAppt = { consulate: apptConsulate, date: apptDate };
await chrome.storage.local.set({ "ctx_currentAppt": ctx.currentAppt }); await chrome.storage.local.set({ "ctx_currentAppt": ctx.currentAppt });
} }
@ -568,6 +592,19 @@ async function runner() {
if (processedConsulates > 0) { if (processedConsulates > 0) {
break; break;
} }
// Reset all soft bans in the first 5 minutes of the first operational hour
let now = new Date();
if (isNoBanTime(cfg.frequency)) {
let nextCheckAt = new Date(ctx.consulates[c].nextCheckAt);
let differenceInMinutes = (nextCheckAt.getTime() - now.getTime()) / (1000 * 60);
if (differenceInMinutes > cfg.frequency) {
console.log(`Resetting soft ban for ${c}`);
ctx.consulates[c].nextCheckAt = getFutureDate(0, cfg.frequency);
}
}
// skip if not time to check // skip if not time to check
if (ctx.consulates[c].nextCheckAt > new Date().toISOString()) { if (ctx.consulates[c].nextCheckAt > new Date().toISOString()) {
continue; continue;
@ -579,7 +616,7 @@ async function runner() {
console.log(msg); console.log(msg);
await chrome.storage.local.set({ "ctx_statusMsg": msg }); await chrome.storage.local.set({ "ctx_statusMsg": msg });
let availDates = await getAvailableDates(ctx.consulates[c].id); let availDates = await getAvailableDates(ctx.consulates[c].id);
ctx.consulates[c].nextCheckAt = getFutureDate(cfg.frequency, getJitter(cfg.frequency)); ctx.consulates[c].nextCheckAt = getFutureDate(cfg.frequency, cfg.frequency);
if (!availDates) { if (!availDates) {
msg = `Failed to fetch available dates in ${c}`; msg = `Failed to fetch available dates in ${c}`;
@ -590,21 +627,16 @@ async function runner() {
// 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 // wait for some time before checking again
let now = new Date();
let currentHourUTC = now.getUTCHours();
let currentMinuteUTC = now.getUTCMinutes();
if (availDates.length == 0) { if (availDates.length == 0) {
msg = `No available dates in ${c}, probably banned`; msg = `No available dates in ${c}`;
console.log(msg); console.log(msg);
await chrome.storage.local.set({ "ctx_statusMsg": msg }); await chrome.storage.local.set({ "ctx_statusMsg": msg });
// Only set SOFT_BAN_TIMEOUT if it's not the first 5 minutes of 23pm UTC if (!isNoBanTime(cfg.frequency)) {
if (!(currentHourUTC === 23 && currentMinuteUTC < 5)) { console.log(`Setting soft ban for ${c}`);
ctx.consulates[c].nextCheckAt = getFutureDate(SOFT_BAN_TIMEOUT, getJitter(cfg.frequency)); ctx.consulates[c].nextCheckAt = getFutureDate(SOFT_BAN_TIMEOUT, cfg.frequency);
} }
ctx.consulates[c].currentDate = null; ctx.consulates[c].currentDate = null;
continue; continue;
} }
@ -650,7 +682,7 @@ async function runner() {
continue; continue;
} }
console.log(`Available timeslots in ${c} at ${chosenDate}: ${availTimes}`); console.log(`Available timeslots in ${c} at ${chosenDate}: ${availTimes}`);
let chosenTime = availTimes[0]; let chosenTime = availTimes[availTimes.length - 1];
// fill timeslot in reschedule form // fill timeslot in reschedule form
await delay(PAGE_WAIT_TIME); await delay(PAGE_WAIT_TIME);