/** * NOTE: install "dark mode" on browser because tesseract need contract to detect text * NOTE: zoom 120% on browser because below */ const robotjs = require('robotjs') const tesseract = require('tesseract.js') const jsdom = require('jsdom') const Jimp = require('jimp') const CONFIG = { SCALE_IMAGE: 1.5, SCROLL_COUNT: 8, } module.exports = async function(keywordSearch, keywordToClick, scale = CONFIG.SCALE_IMAGE, fileScreenshot = 'screenshot.jpg', waitSearch = 2000) { if(!scale) { scale = CONFIG.SCALE_IMAGE } if(!fileScreenshot) { fileScreenshot = 'screenshot.jpg' } if(!waitSearch) { waitSearch = 2000 } const $_randomInteger = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; } async function handleToClick() { let _horc = ''; let _text = ''; let _coorStr = ''; const _captureImage = async () => { const capture = robotjs.screen.capture() return new Promise(res => { new Jimp( {data: capture.image, width: capture.width, height: capture.height}, (err, image) => { image.greyscale((err, image) => { image.scale(scale, (err, image) => { image.writeAsync(fileScreenshot).then(() => { res(true) }) }) }); }); }) } const _convertImageToDomString = async () => { await tesseract .recognize(fileScreenshot) .then(async ({data: {hocr, text}}) => { _horc = hocr _text = text }) } const _detectHTML = async () => { console.log({keywordToClick, _text}) return new Promise(async (resToFinished, rejToAgain) => { if(_text.includes(keywordToClick)) { const dom = new jsdom.JSDOM(_horc) const spanEls = dom.window.document.querySelectorAll('span') for await(let span of spanEls) { const textContent = span.textContent.split(' ').join('') if(textContent.includes(keywordToClick)) { _coorStr = span.title return resToFinished(true) } } } // scroll to 8 times for (let i = 1; i < CONFIG.SCROLL_COUNT; i++) { robotjs.keyTap('down') } rejToAgain(false) }) } async function _handleClick() { const [type, left, top, right, bottom] = _coorStr.split(' ') const x = parseInt((parseInt(left) + $_randomInteger(20, 40)) / scale) const y = parseInt((parseInt(top) - $_randomInteger(0, parseInt(top) - parseInt(bottom))) / scale) robotjs.moveMouse(x, y) robotjs.mouseClick('left') console.log('moveMouse:', {x, y}, { left, bottom, right, top }) } return new Promise(async (res, rej) => { await _captureImage(); await _convertImageToDomString(); await _detectHTML().then(_handleClick).catch(rej); }) } await (async function search() { robotjs.keyTap('home', ['alt']); robotjs.typeString(keywordSearch); robotjs.keyTap('enter') return new Promise(res => setTimeout(res, waitSearch)) }()) await (async function recusiveScroll(countScroll = 1, limitStopScroll = 20) { if(countScroll > limitStopScroll) { return; } await handleToClick(keywordToClick, scale) .catch(async () => { await recusiveScroll(++countScroll, limitStopScroll) }) }()) }