diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8853668 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +from node:18 + +RUN apt update +RUN apt install -y chromium + +WORKDIR /app +COPY package.json . +RUN npm install +COPY . . +ENTRYPOINT ["node", "__tests__/index.js"] + + diff --git a/README.md b/README.md index 31cfd96..72795e9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# Termin in Berlin + Я не настоящий сварщик. Скрипт подкинули друзья на просторах интернета, я его подхачил под себя и запустил. После клонирования запускаем `nmp install` в корне репозитория - это поставит нужные модули. @@ -6,3 +8,32 @@ Запускал из файлика `__tests__/index.js` конфигурацией `Current file`, тут важно что не `Check termins` - это почему-то не работало) На 10 декабря 2022 скрипт помог найти термин за 5 дней и 26000 итераций. + +### Configure `beep`: + +Personnaly I use telegram message. +Thus use https://t.me/BotFather to create a bot +Next configure token and chat id +Optionally you can configure the notification message. + +``` +const bot_token = "dummytoken"; +const chat_id = "31337"; +const notification_text = "Termin calls!"; +``` + + +### dockerize +``` +docker build . -t termin +``` + +### Run on Mac: +``` +xhost + ${hostname} +ip=$(ifconfig en0 | grep inet | awk '$1=="inet" {print $2}') +docker run --rm -it -e DISPLAY=$ip:0 -v /tmp/.X11-unix:/tmp/.X11-unix termin +``` + +xhost is required for x11 +to setup xhost use https://gist.github.com/sorny/969fe55d85c9b0035b0109a31cbcb088 guide \ No newline at end of file diff --git a/__tests__/index.js b/__tests__/index.js index 9ff9d89..0c96e6c 100644 --- a/__tests__/index.js +++ b/__tests__/index.js @@ -1,131 +1,157 @@ -const fs = require('fs'); -const path = require('path'); -const puppeteer = require('puppeteer-extra') -const StealthPlugin = require('puppeteer-extra-plugin-stealth') -const {exec} = require("child_process"); - -puppeteer.use(StealthPlugin()) - -puppeteer.launch({ headless: false, product: 'chrome' }).then(async browser => { - let count = 0; - let page = await browser.newPage(); - while (true) { - let time = Math.floor(Date.now() / 1000); - try { - page = await browser.newPage() - await page.setViewport({ width: 800, height: 600 }) - await page.setDefaultTimeout(60000); - - await page.goto('https://otv.verwalt-berlin.de/ams/TerminBuchen'); - await page.waitForXPath('//a[text()="Termin buchen"]').then(e => e.click()); - await page.waitForNavigation(); - await page.waitForSelector('.loading', {visible: true}); - await page.waitForSelector('.loading', {hidden: true}); - await page.click('#xi-cb-1'); - await page.click('#applicationForm\\:managedForm\\:proceed'); - await page.waitForNavigation(); - await page.waitForSelector('.loading', {visible: true}); - await page.waitForSelector('.loading', {hidden: true}); - - await page.waitForTimeout(3000); - await page.select('#xi-sel-400', '160'); - - await page.waitForTimeout(3000); - await page.select('#xi-sel-422', '2'); - - await page.waitForTimeout(3000); - await page.select('#xi-sel-427', '1'); - - await page.waitForTimeout(3000); - await page.select('#xi-sel-428', '160-0'); - - await page.waitForTimeout(3000); - await page.waitForXPath('//p[contains(text(), "Aufenthaltstitel - beantragen")]').then(e => e.click()); - await page.waitForXPath('//p[contains(text(), "Erwerbstätigkeit")]').then(e => e.click()); - - await page.waitForTimeout(3000); - await page.waitForSelector('#SERVICEWAHL_DE160-0-1-1-324659') - await page.click('#SERVICEWAHL_DE160-0-1-1-324659') - await page.waitForSelector('.loading', {visible: true}); - await page.waitForSelector('.loading', {hidden: true}); - await page.waitForSelector('.loading', {hidden: true}); - - await page.waitForTimeout(3000); - count = count + 1; - await page.waitForSelector('#applicationForm\\:managedForm\\:proceed'); - await page.click('#applicationForm\\:managedForm\\:proceed'); - - await page.waitForSelector('.loading', {visible: true}); - await page.waitForSelector('.loading', {hidden: true}); - await page.waitForSelector('.loading', {hidden: true}); - - - //await expect(page).toMatchElement('#messagesBox > ul > li.errorMessage'); - //await page.waitForSelector('.errorMessage', {timeout:5000}) - await page.waitForXPath("//li[@class='antcl_active'][span='Servicewahl']", {timeout: 5000}) - //console.log("selector with error message found") - await page.waitForTimeout(3000); - - //await page.click('#applicationForm\\:managedForm\\:proceed'); - //await page.waitForTimeout(5000); - await page.waitForSelector('#applicationForm\\:managedForm\\:proceed'); - - - while (Math.floor(Date.now() / 1000) - time < 60 * 25) { - count = count + 1; - await page.click('#applicationForm\\:managedForm\\:proceed'); - - await page.waitForSelector('.loading', {visible: true}); - await page.waitForSelector('.loading', {hidden: true}); - await page.waitForSelector('.loading', {hidden: true}); - await page.waitForTimeout(3000); - - //await expect(page).toMatchElement('#messagesBox > ul > li.errorMessage'); - await page.waitForXPath("//li[@class='antcl_active'][span='Servicewahl']", {timeout: 15000}) - await page.waitForSelector('#applicationForm\\:managedForm\\:proceed'); - //console.log("selector with error message found") - await page.waitForTimeout(1000); - console.log("try " + count + " failed"); - } - await page.waitForTimeout(3000) - - await page.close(); - - } catch (e) { - let i = 0; - console.log("caught exception "+e + " on count " + count); - while (i < 3) { - console.log('\x07'); - i += 1; - } - //let path1 = path.join(__dirname, 'e2e', 'screenshots'); - //await fs.promises.mkdir(path1, {recursive: true}); - //await page.screenshot({path: `${path1}/screenshot.png`}); - let j = 0; - while (j < 20) { - exec('beep'); - j = j+1; - } - await page.waitForTimeout(1000 * 60 * 5); - } - } -}) - -/*describe('Check termins', () => { - beforeAll( async () => { - - // Set a definite size for the page viewport so view is consistent across browsers - await page.setViewport( { - width: 1366, - height: 768, - deviceScaleFactor: 1 - } ); - } ); - - it( 'should NOT have termins', async () => { - - - - } - }) -});*/ +const fs = require('fs'); +const path = require('path'); +const puppeteer = require('puppeteer-extra') +const StealthPlugin = require('puppeteer-extra-plugin-stealth') +const {exec} = require("child_process"); + +const bot_token = "dummytoken"; +const chat_id = "31337"; +const notification_text = "Termin calls!"; + + +puppeteer.use(StealthPlugin()) + +const puppeteerOptions = { + headless: false, + ignoreHTTPSErrors: true, + args: [ + '--no-sandbox', + '--single-process', + ], + ignoreDefaultArgs: ["--enable-automation"], + executablePath: '/usr/bin/chromium' +} + +const init = async () => { + browser = await puppeteer.launch(puppeteerOptions) + let count = 0; + let page = (await browser.pages())[0]; + + + while (true) { + let time = Math.floor(Date.now() / 1000); + try { + if ((await browser.pages()).length == 0 ){ + page = await browser.newPage() + } + await page.setViewport({ width: 800, height: 600 }) + await page.setDefaultTimeout(60000); + + await page.goto('https://otv.verwalt-berlin.de/ams/TerminBuchen'); + await page.waitForXPath('//a[text()="Termin buchen"]').then(e => e.click()); + await page.waitForNavigation(); + await page.waitForSelector('.loading', {visible: true}); + await page.waitForSelector('.loading', {hidden: true}); + await page.click('#xi-cb-1'); + await page.click('#applicationForm\\:managedForm\\:proceed'); + await page.waitForNavigation(); + await page.waitForSelector('.loading', {visible: true}); + await page.waitForSelector('.loading', {hidden: true}); + + await page.waitForTimeout(3000); + await page.select('#xi-sel-400', '160'); + + await page.waitForTimeout(3000); + await page.select('#xi-sel-422', '2'); + + await page.waitForTimeout(3000); + await page.select('#xi-sel-427', '1'); + + await page.waitForTimeout(3000); + await page.select('#xi-sel-428', '160-0'); + + await page.waitForTimeout(3000); + await page.waitForXPath('//p[contains(text(), "Aufenthaltstitel - beantragen")]').then(e => e.click()); + await page.waitForXPath('//p[contains(text(), "Erwerbstätigkeit")]').then(e => e.click()); + + await page.waitForTimeout(3000); + await page.waitForSelector('#SERVICEWAHL_DE160-0-1-1-324659') + await page.click('#SERVICEWAHL_DE160-0-1-1-324659') + await page.waitForSelector('.loading', {visible: true}); + await page.waitForSelector('.loading', {hidden: true}); + await page.waitForSelector('.loading', {hidden: true}); + + await page.waitForTimeout(3000); + count = count + 1; + await page.waitForSelector('#applicationForm\\:managedForm\\:proceed'); + await page.click('#applicationForm\\:managedForm\\:proceed'); + + await page.waitForSelector('.loading', {visible: true}); + await page.waitForSelector('.loading', {hidden: true}); + await page.waitForSelector('.loading', {hidden: true}); + + + //await expect(page).toMatchElement('#messagesBox > ul > li.errorMessage'); + //await page.waitForSelector('.errorMessage', {timeout:5000}) + await page.waitForXPath("//li[@class='antcl_active'][span='Servicewahl']", {timeout: 5000}) + //console.log("selector with error message found") + await page.waitForTimeout(3000); + + //await page.click('#applicationForm\\:managedForm\\:proceed'); + //await page.waitForTimeout(5000); + await page.waitForSelector('#applicationForm\\:managedForm\\:proceed'); + + + while (Math.floor(Date.now() / 1000) - time < 60 * 25) { + count = count + 1; + await page.click('#applicationForm\\:managedForm\\:proceed'); + + await page.waitForSelector('.loading', {visible: true}); + await page.waitForSelector('.loading', {hidden: true}); + await page.waitForSelector('.loading', {hidden: true}); + await page.waitForTimeout(3000); + + //await expect(page).toMatchElement('#messagesBox > ul > li.errorMessage'); + await page.waitForXPath("//li[@class='antcl_active'][span='Servicewahl']", {timeout: 15000}) + await page.waitForSelector('#applicationForm\\:managedForm\\:proceed'); + //console.log("selector with error message found") + await page.waitForTimeout(1000); + console.log("try " + count + " failed"); + } + await page.waitForTimeout(3000) + + await page.close(); + + } catch (e) { + let i = 0; + console.log("caught exception "+e + " on count " + count); + while (i < 3) { + console.log('\x07'); + i += 1; + } + //let path1 = path.join(__dirname, 'e2e', 'screenshots'); + //await fs.promises.mkdir(path1, {recursive: true}); + //await page.screenshot({path: `${path1}/screenshot.png`}); + let j = 0; + while (j < 20) { + // replace this with something like + // wget 'https://api.telegram.org/bot{bot_token}/sendMessage?chat_id={chat_id}&text={notification_text}' + exec(`wget 'https://api.telegram.org/bot${bot_token}/sendMessage?chat_id=${chat_id}&text=${notification_text}'`); + // exec('beep'); + j = j+1; + } + await page.waitForTimeout(1000 * 60 * 5); + } + } +} + +init() + +/*describe('Check termins', () => { + beforeAll( async () => { + + // Set a definite size for the page viewport so view is consistent across browsers + await page.setViewport( { + width: 1366, + height: 768, + deviceScaleFactor: 1 + } ); + } ); + + it( 'should NOT have termins', async () => { + + + + } + }) +});*/