Last active
July 16, 2024 10:29
-
-
Save sorinmircea/e9c4bc6945b82d496fac0659696c76dd to your computer and use it in GitHub Desktop.
FMEL auto-checker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 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