POF for retrying extension

This commit is contained in:
Maks Snegov 2024-04-19 22:14:53 -07:00
parent 1b955f06ed
commit b5b6ca363d
11 changed files with 256 additions and 50 deletions

View File

@ -1,45 +0,0 @@
// Function to send POST request
function sendPostRequest(data) {
fetch('https://ntfy.sh/snegov', {
method: 'POST', // PUT works too
body: `US visa: ${data}`
})
.then(response => {
console.log('POST request sent successfully:', data);
})
.catch((error) => {
console.error('Error sending POST request:', error);
});
}
function checkDate() {
const targetElement = document.querySelector('.swal2-html-container');
// Get current time
const currentTime = new Date();
const formattedTime = currentTime.toISOString();
if (targetElement) {
const availabilitySpan = targetElement.querySelector('span[style="color: lightgreen;"]');
const appointmentSpan = targetElement.querySelector('span[style="color: orange"]');
const date_avail = availabilitySpan ? availabilitySpan.textContent.match(/Latest availability: (.*)\./)[1].trim() : null;
const date_booked = appointmentSpan ? appointmentSpan.textContent.match(/Your current appointment is on (.*)/)[1].trim() : null;
if (date_avail && date_booked) {
const date_avail_date = new Date(date_avail);
const date_booked_date = new Date(date_booked);
console.log(`${formattedTime}: available date ${date_avail}; booked on ${date_booked}`);
// Compare the dates
if (date_avail_date < date_booked_date) {
const message = `available date ${date_avail}; booked on ${date_booked}`;
sendPostRequest(message);
}
}
} else {
console.log('Element with class "swal2-html-container" not found');
}
}
// Set an interval to check the date every 10 seconds
setInterval(checkDate, 20000);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
images/icon_passport_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

BIN
images/icon_passport_48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,12 +1,25 @@
{
"manifest_version": 3,
"name": "Page Change Detector",
"version": "1.0",
"permissions": ["activeTab"],
"name": "not-a-rescheduler",
"version": "0.0.1",
"permissions": [ "storage", "tabs", "activeTab", "notifications", "declarativeContent" ],
"content_scripts": [
{
"matches": ["https://ais.usvisa-info.com/*"],
"js": ["content.js"]
"js": ["scripts/content.js"]
}
]
],
"action": {
"default_popup": "popup/popup.html",
"default_icon": "images/icon_passport_48.png"
},
"background": {
"service_worker": "background.js"
},
"icons": {
"16": "images/icon_passport_16.png",
"48": "images/icon_passport_48.png",
"128": "images/icon_passport_128.png",
"512": "images/icon_passport_512.png"
}
}

6
popup/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

9
popup/popup.css Normal file
View File

@ -0,0 +1,9 @@
#saveStatus {
opacity: 0;
transition: opacity 0.5s;
color: green;
}
#saveStatus.show {
opacity: 1;
}

59
popup/popup.html Normal file
View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>not-a-rescheduler popup</title>
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="popup.css">
<style>
/* Set a minimum width for the body */
body {
min-width: 300px; /* Adjust the value as desired */
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12">
<h3 style="white-space: nowrap;">not-a-rescheduler<br><span id="version"></span></h3>
</div>
</div>
<div class="row">
<div class="col">
<div class="form-check form-switch" style="text-align: left;">
<input class="form-check-input" type="checkbox" role="switch" id="activate">
<label class="form-check-label" for="activate">Activate the script</label>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="form-group mb-2">
<label for="username">Username</label>
<input type="text" class="form-control" id="username" placeholder="Username">
</div>
<div class="form-group mb-2">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password">
<button type="button" id="showPassword" class="btn btn-link btn-sm">Show password</button>
</div>
<div class="mb-2">
<button type="button mb-2" class="btn btn-primary" id="saveButton">Save credentials</button>
<span id="saveStatus">Saved!</span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="mb-2">
<input type="range" id="frequency" name="frequency" min="1" max="10" step="0.5">
<label for="frequency">Frequency of checks<br>(every <span id="frequency_info">1</span> minutes)</label>
</div>
</div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>

68
popup/popup.js Normal file
View File

@ -0,0 +1,68 @@
(async function() {
const $version = await new Promise(r => chrome.management.getSelf(self => r(self.version)));
document.getElementById("version").innerText = `v${$version}`;
await chrome.storage.local.get().then(items => {
document.getElementById("activate").checked = items["__activate"] || false;
document.getElementById("username").value = items["__username"] || "";
document.getElementById("password").value = items["__password"] || "";
document.getElementById("frequency").value = items["__frequency"] || 1;
document.getElementById("frequency_info").innerText = items["__frequency"] || 1;
});
chrome.storage.onChanged.addListener((changes, area) => {
if (changes.__frequency)
document.getElementById("frequency_info").innerText = changes.__frequency.newValue;
});
// activate checkbox
document.getElementById("activate").addEventListener("change", async e => {
await chrome.storage.local.set({ "__activate": e.target.checked });
});
// credentials
let usernameField = document.getElementById("username");
let passwordField = document.getElementById("password");
let showPasswordButton = document.getElementById("showPassword");
let saveCredsButton = document.getElementById("saveButton");
let saveStatusElement = document.getElementById("saveStatus");
async function save_credentials() {
await chrome.storage.local.set({
"__username": usernameField.value,
"__password": passwordField.value
});
saveStatusElement.classList.add("show");
setTimeout(() => {
saveStatusElement.classList.remove("show");
}, 2000);
}
usernameField.addEventListener("keypress", async e => {
if (e.key === "Enter") {
await save_credentials();
}
});
passwordField.addEventListener("keypress", async e => {
if (e.key === "Enter") {
await save_credentials();
}
});
saveCredsButton.addEventListener("click", async () => {
await save_credentials();
});
showPasswordButton.addEventListener("mousedown", function() {
passwordField.type = "text";
});
showPasswordButton.addEventListener("mouseup", function() {
passwordField.type = "password";
});
// frequency range slider
document.getElementById("frequency").addEventListener("change", function() {
chrome.storage.local.set({ __frequency: this.value });
});
})();

96
scripts/content.js Normal file
View File

@ -0,0 +1,96 @@
function log_ts(message) {
console.log(new Date().toISOString() + " " + message);
}
async function checkDates() {
log_ts('checkDates start');
config.countdown = config.frequency * minute;
await chrome.storage.local.set({ "__countdown": config.countdown });
log_ts('checkDates done');
}
async function runner() {
// log_ts('runner start');
let prev_config = Object.assign({}, config);
let result = await new Promise(resolve => chrome.storage.local.get(null, resolve));
config.activate = result['__activate'] || false;
config.username = result['__username'] || "";
config.password = result['__password'] || "";
config.frequency = result['__frequency'] || 1;
config.countdown = result['__countdown'] || 0;
if (prev_config.activate === null) {
log_ts('Reading config: ' + JSON.stringify(config));
return;
}
let configChanged = false;
for (let key in config) {
if (config.hasOwnProperty(key) && config[key] !== prev_config[key]) {
log_ts(`Config change: ${key}, ${prev_config[key]} => ${config[key]}`);
configChanged = true;
// reduce countdown if frequency is reduced
if (key === 'frequency') {
let max_countdown = config[key] * minute;
if (config.countdown > max_countdown) {
config.countdown = max_countdown;
await chrome.storage.local.set({ "__countdown": config.countdown });
}
}
}
}
if (configChanged) {
// print whole config
log_ts(JSON.stringify(config));
}
if (config.activate && !prev_config.activate) {
log_ts('Activating extension');
config.countdown = 5;
}
if (!config.activate) {
// reset countdown when deactivating the extension
if (prev_config.activate) {
log_ts('Deactivating extension');
config.countdown = 0;
await chrome.storage.local.set({ "__countdown": config.countdown });
}
return;
}
if (config.username === "" || config.password === "") {
log_ts('Username or password is empty');
return;
}
if (config.frequency <= 0) {
log_ts('Frequency is 0');
return;
}
if (config.countdown > 0) {
config.countdown -= 1;
log_ts(`Countdown: ${config.countdown}`);
await chrome.storage.local.set({ "__countdown": config.countdown });
return;
}
checkDates();
// log_ts('runner done');
}
let config = {
activate: null,
username: null,
password: null,
frequency: null,
countdown: null,
};
let minute = 60;
setInterval(runner, 1000);