Skip to content

Instantly share code, notes, and snippets.

@sorinmircea
Last active July 16, 2024 10:29
Show Gist options
  • Select an option

  • Save sorinmircea/e9c4bc6945b82d496fac0659696c76dd to your computer and use it in GitHub Desktop.

Select an option

Save sorinmircea/e9c4bc6945b82d496fac0659696c76dd to your computer and use it in GitHub Desktop.
FMEL auto-checker
const puppeteer = require('puppeteer');
require('dotenv').config()
const Sentry = require('@sentry/node');
Sentry.init({ dsn: process.env.SENTRY_DSN });
var cron = require('node-cron');
var http = require('http');
var HOUSES_FOR_DATE = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
var EVERY_MINUTES = 3
cron.schedule('*/' + EVERY_MINUTES + ' * * * *', async () => {
console.log(Date.now(), " starting job");
(async () => {
doProcess()
})();
});
async function doProcess() {
const browser = await puppeteer.launch({
'args': [
'--no-sandbox',
'--disable-setuid-sandbox'
]
});
// const browser = await puppeteer.launch({
// headless: false,
// args: ['--start-fullscreen']
// });
const page = await browser.newPage();
// Open Web Page
await page.goto('https://accommodation.fmel.ch/StarRezPortal/AE18865B/7/8/Login-Login?IsContact=False');
// Login
await page.keyboard.type(process.env.EMAIL);
await page.keyboard.down('Tab');
await page.keyboard.up('Tab');
await page.keyboard.type(process.env.PASSWORD);
await delay(5000);
await autoScroll(page);
await page.click('.login-button button')
await page.waitForNavigation();
// Continue Booking
await page.click('a img')
// Get the available booking dates
await autoScroll(page);
var datesDescription = await getDatesDescription(page)
if (datesDescription != process.env.DATES) {
// Dates have changed ... SHOW ERROR
console.log("Change in dates, announcing !!")
try {
var errorMsg = Date.now().toString() + " - FMEL dates of registration were updated"
throw new Error(errorMsg)
} catch (err) {
Sentry.captureException(err);
}
}
// See accomodations for given date
var datesSplit = datesDescription.split(';')
for (var leIndex = 0; leIndex < datesSplit.length; leIndex++) {
if(datesSplit[leIndex].length == 0) {
continue;
}
await page.evaluate((index) => {
debugger;
document.querySelectorAll('.ui-actions button')[index].click();
}, leIndex);
await page.waitForNavigation();
await autoScroll(page);
var crtHouses = await getStringOfHouses(page)
if(HOUSES_FOR_DATE[leIndex] != -1 && crtHouses != HOUSES_FOR_DATE[leIndex]) {
try {
var errorMsg = ` Date.now().toString()−dateindex{leIndex} houses changed from HOUSESFORDATE[leIndex]to{crtHouses}`
throw new Error(errorMsg)
} catch (err) {
Sentry.captureException(err);
}
}
HOUSES_FOR_DATE[leIndex] = crtHouses
await page.goBack();
}
console.log(Date.now(), ` job done; state is ${HOUSES_FOR_DATE}`);
await browser.close();
}
function delay(time) {
return new Promise(function (resolve) {
setTimeout(resolve, time)
});
}
function getText(linkText) {
linkText = linkText.replace(/\r\n|\r/g, "\n");
linkText = linkText.replace(/\ +/g, " ");
// Replace &nbsp; with a space
var nbspPattern = new RegExp(String.fromCharCode(160), "g");
return linkText.replace(nbspPattern, " ");
}
async function findButton(page, buttonText) {
const buttons = await page.$$('button')
for (var i = 0; i < buttons.length; i++) {
let valueHandle = await buttons[i].getProperty('innerText');
let linkText = await valueHandle.jsonValue();
const text = getText(linkText);
if (text == buttonText) {
return buttons[i];
}
}
return null;
}
async function findLink(page, linkTextToFind) {
const buttons = await page.$$('a')
for (var i = 0; i < buttons.length; i++) {
let valueHandle = await buttons[i].getProperty('innerText');
let linkText = await valueHandle.jsonValue();
const text = getText(linkText);
if (text == linkTextToFind) {
console.log("Found")
return buttons[i];
}
}
return null;
}
async function getNumberOfDates(page) {
var dates = await page.$$('.actioned')
return dates.length
}
async function getNumberOfHouses(page) {
var houses = await page.$$('.action-panel-card')
return houses.length
}
async function getStringOfHouses(page) {
var houses = await page.$$('span.gap-below.title.ui-title')
var housesDescriptions = []
var housesDescriptionsString = ''
for (var i = 0; i < houses.length; i++) {
let valueHandle = await houses[i].getProperty('innerText');
let linkText = await valueHandle.jsonValue();
const text = getText(linkText);
housesDescriptions.push(text);
housesDescriptionsString += text + ";";
}
return housesDescriptionsString;
}
async function getDatesDescription(page) {
var datesDescriptionDOM = await page.$$('.contents-body > span')
var datesDescriptions = []
var datesDescriptionsString = ''
for (var i = 0; i < datesDescriptionDOM.length; i++) {
let valueHandle = await datesDescriptionDOM[i].getProperty('innerText');
let linkText = await valueHandle.jsonValue();
const text = getText(linkText);
datesDescriptions.push(text);
datesDescriptionsString += text + ";";
}
return datesDescriptionsString;
}
async function autoScroll(page) {
await page.evaluate(async () => {
await new Promise((resolve, reject) => {
var totalHeight = 0;
var distance = 100;
var timer = setInterval(() => {
var scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if (totalHeight >= scrollHeight) {
clearInterval(timer);
resolve();
}
}, 100);
});
});
}
http.createServer(function (request, response) {
response.writeHead(200, { "Content-Type": "text/html" });
response.write("<!DOCTYPE \"html\">");
response.write("<html>");
response.write("<head>");
response.write("<title>Hello World Page</title>");
response.write("</head>");
response.write("<body>");
response.write("Hello World!");
response.write("</body>");
response.write("</html>");
response.end();
}).listen(process.env.PORT || 5000);
setInterval(function () {
console.log(Date.now().toString() + " - keeping dyno online")
http.get("http://fmel-checker.herokuapp.com/");
}, 300000); // every 5 minutes (300000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment