// ==UserScript== // @name Hcaptcha Solver with Browser Trainer(Automatically solves Hcaptcha in browser) // @namespace Hcaptcha Solver // @version 10.0 // @description Hcaptcha Solver in Browser | Automatically solves Hcaptcha in browser // @author Md ubeadulla // @match https://*.hcaptcha.com/*hcaptcha-challenge* // @match https://*.hcaptcha.com/*checkbox* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @connect www.imageidentify.com // @connect https://cdnjs.cloudflare.com // @connect https://cdn.jsdelivr.net // @connect https://unpkg.com // @connect https://*.hcaptcha.com/* // @require https://unpkg.com/jimp@0.5.2/browser/lib/jimp.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/tesseract.js/2.0.0-alpha.2/tesseract.min.js // @require https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.13.0/dist/tf.min.js // @require https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd@2.2.2/dist/coco-ssd.min.js // @require https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet@2.1.0/dist/mobilenet.min.js /* ██╗░░██╗░█████╗░░█████╗░██████╗░████████╗░█████╗░██╗░░██╗░█████╗░  ░██████╗░█████╗░██╗░░░░░██╗░░░██╗███████╗██████╗░ ██║░░██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗██║░░██║██╔══██╗  ██╔════╝██╔══██╗██║░░░░░██║░░░██║██╔════╝██╔══██╗ ███████║██║░░╚═╝███████║██████╔╝░░░██║░░░██║░░╚═╝███████║███████║  ╚█████╗░██║░░██║██║░░░░░╚██╗░██╔╝█████╗░░██████╔╝ ██╔══██║██║░░██╗██╔══██║██╔═══╝░░░░██║░░░██║░░██╗██╔══██║██╔══██║  ░╚═══██╗██║░░██║██║░░░░░░╚████╔╝░██╔══╝░░██╔══██╗ ██║░░██║╚█████╔╝██║░░██║██║░░░░░░░░██║░░░╚█████╔╝██║░░██║██║░░██║  ██████╔╝╚█████╔╝███████╗░░╚██╔╝░░███████╗██║░░██║ ╚═╝░░╚═╝░╚════╝░╚═╝░░╚═╝╚═╝░░░░░░░░╚═╝░░░░╚════╝░╚═╝░░╚═╝╚═╝░░╚═╝  ╚═════╝░░╚════╝░╚══════╝░░░╚═╝░░░╚══════╝╚═╝░░╚═╝ */ /** Note: This script is solely intended for the use of educational purposes only and not to abuse any website. * Sign Up using the referral links or consider a donation to the following addresses: *************************************************************************************************** * Faucets: * * Install the free cryporotator https://greasyfork.org/en/scripts/426599-free-cryptorotator * * Or Sign up using the referral link and solve captchas to earn crypto (Do not abuse the websites)* * 1.) https://get-bitcoin.net/?ref=9230 * * 2.) https://getdoge.io/?ref=34017 * * 3.) https://r.adbtc.top/1771513 * * 4.) https://cryptowin.io/ref/ubeadulla * * 5.) https://winalittle.fun/referral/02c7061877cec89e81a306303d36b77c * * 6.) https://faucetofbob.xyz/?ref=2121 * * 7.) https://free-litecoin.com/login?referer=1035367 * * 8.) https://free-ethereum.io/?referer=742436 * * 9.) https://litking.biz/signup?r=125431 * * 10.) https://bitking.biz/signup?r=75339 * *************************************************************************************************** * MicroWallets: * * 1.) FaucetPay: BTC: 1HeD2a11n8d9zBTaznNWfVxtw1dKuW2vT5 * * LTC: MHpCuD3zAFEkeuhbgLbuZKcfdqMFkaLSem * * BCH: bitcoincash:qp7ywra8h7lwatcuc7u65lv8x6rv5kn4sutrsnzrpx * * TRX: TLs3iQfXJs1rmUuG6pkLkUwcu32mFUwzgu * * Doge: DPtBQG9GNTYHUFkjB2zYWYah4nCCogVAt9 * * * 2.) Direct BTC: 35HbfGfvbdctzY6tT4jcHXRx4zonBTnDuC * *************************************************************************************************** * Cloud Mining Websites Just SignUp and earn passive income * * * 1.) https://tronrex.online/r/86733 * * * *************************************************************************************************** */ // @downloadURL https://update.greasyfork.icu/scripts/498381/Hcaptcha%20Solver%20with%20Browser%20Trainer%28Automatically%20solves%20Hcaptcha%20in%20browser%29.user.js // @updateURL https://update.greasyfork.icu/scripts/498381/Hcaptcha%20Solver%20with%20Browser%20Trainer%28Automatically%20solves%20Hcaptcha%20in%20browser%29.meta.js // ==/UserScript== (async function() { //TODO: Enable debug mode to print console logs //TODO: Refactor Code for different models 'use strict'; var selectedImageCount = 0; var tensorFlowModel = undefined; var tensorFlowMobileNetModel = undefined; var worker = undefined; var identifiedObjectsList = []; var exampleImageList = []; var identifyObjectsFromImagesCompleted = false; var currentExampleUrls = []; //Default Language for hcaptcha const LANG_ENGLISH = "English" const DEFAULT_LANGUAGE = LANG_ENGLISH; const ENABLE_DEFAULT_LANGUAGE = true; //Guess/Match New Images const MATCH_IMAGES_USING_TRAINER = false; const GUESS_NEW_IMAGE_TYPE = false; //Node Selectors const CHECK_BOX = "#checkbox"; const SUBMIT_BUTTON = ".button-submit"; const TASK_IMAGE_BORDER = ".task-image .border"; const IMAGE = ".task-image .image"; const TASK_IMAGE = ".task-image"; const PROMPT_TEXT = ".prompt-text"; const NO_SELECTION = ".no-selection"; const CHALLENGE_INPUT_FIELD = ".challenge-input .input-field"; const CHALLENGE_INPUT = ".challenge-input"; const CHALLENGE_IMAGE = ".challenge-example .image .image"; const IMAGE_FOR_OCR = ".challenge-image .zoom-image"; const LANGUAGE_SELECTOR = "#language-list .scroll-container .option span"; //Attributes const ARIA_CHECKED = "aria-checked"; const ARIA_HIDDEN = "aria-hidden"; //Values that can be changed for other languages const AIRPLANE = "airplane"; const BICYCLE = "bicycle"; const BOAT = "boat"; const BUS = "bus"; const CAR = "car"; const MOTORBUS = "motorbus"; const MOTORCYCLE = "motorcycle"; const SURFBOARD = "surfboard"; const TRAIN = "train"; const TRUCK = "truck"; const TRIMARAN = "trimaran"; const SEAPLANE = "seaplane"; const SPEEDBOAT = "speedboat"; //Living Room Objects const BED = "bed"; const BOOK = "book"; const CHAIR = "chair"; const CLOCK = "clock"; const COUCH = "couch"; const DINING_TABLE = "dining table"; const POTTED_PLANT = "potted plant"; const TV = "tv"; //Animals const ZEBRA = "zebra"; const CAT = "cat"; const DOG = "dog"; // Vertical River const VALLEY = "valley"; const VERTICAL_RIVER = "vertical river"; const LIVING_ROOM_TYPES = [BED, BOOK, CHAIR, CLOCK, COUCH, DINING_TABLE, POTTED_PLANT, TV]; const TRANSPORT_TYPES = [AIRPLANE, BICYCLE, BOAT, BUS, CAR, MOTORBUS, MOTORCYCLE, SEAPLANE, SPEEDBOAT, SURFBOARD, TRAIN, TRIMARAN, TRUCK]; const ANIMAL_TYPES = [ZEBRA, CAT, DOG]; const SENTENCE_TEXT_A = "Please click each image containing a "; const SENTENCE_TEXT_AN = "Please click each image containing an "; const LANGUAGE_FOR_OCR = "eng"; // Option to override the default image matching // Enabling this by default const ENABLE_TENSORFLOW = true; // Max Skips that can be done while solving the captcha // This is likely not to happen, if it occurs retry for new images const MAX_SKIPS = 10; var skipCount = 0; var USE_MOBILE_NET = false; var USE_COLOUR_PATTERN = false; var NEW_WORD_IDENTIFIED = false; //Probablility for objects var probabilityForObject = new Map(); probabilityForObject.set("speedboat", 0.14); probabilityForObject.set("fireboat", 0.4); probabilityForObject.set("boathouse", 0.4); probabilityForObject.set("submarine", 0.5); probabilityForObject.set("printer", 0.05); probabilityForObject.set("stretcher", 0.05); probabilityForObject.set("rotisserie", 0.02); probabilityForObject.set("spatula", 0.05); String.prototype.includesOneOf = function(arrayOfStrings) { //If this is not an Array, compare it as a String if (!Array.isArray(arrayOfStrings)) { return this.toLowerCase().includes(arrayOfStrings.toLowerCase()); } for (var i = 0; i < arrayOfStrings.length; i++) { if ((arrayOfStrings[i].substr(0, 1) == "=" && this.toLowerCase() == arrayOfStrings[i].substr(1).toLowerCase()) || (this.toLowerCase().includes(arrayOfStrings[i].toLowerCase()))) { return true; } } return false; } String.prototype.equalsOneOf = function(arrayOfStrings) { //If this is not an Array, compare it as a String if (!Array.isArray(arrayOfStrings)) { return this.toLowerCase() == arrayOfStrings.toLowerCase(); } for (var i = 0; i < arrayOfStrings.length; i++) { if ((arrayOfStrings[i].substr(0, 1) == "=" && this.toLowerCase() == arrayOfStrings[i].substr(1).toLowerCase()) || (this.toLowerCase() == arrayOfStrings[i].toLowerCase())) { return true; } } return false; } // This script uses imageidentify API (wolfram) . You may also use TensorFlow.js, Yolo latest version to recognize common objects. //(When the cloud service is available for yolo, we can switch the API endpoint). Accuracy varies between Wolfram, Tensorflow and Yolo. // Use this as a reference to solve recaptcha/other captchas using scripts in browser. This is intended for learning purposes. // Using TensorFlow as fallback, but this requires good CPU in order to solve quickly. // CPU utilization and memory utlization may go high when using TensorFlow.js function matchImages(imageUrl, word, i) { GM_xmlhttpRequest({ method: "POST", url: "https://www.imageidentify.com/objects/user-26a7681f-4b48-4f71-8f9f-93030898d70d/prd/urlapi/", headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: "image=" + encodeURIComponent(imageUrl), timeout: 8000, onload: function(response) { clickImages(response, imageUrl, word, i) }, onerror: function(e) { //Using Fallback TensorFlow if (e && e.status && e.status != 0) { console.log(e); console.log("Using Fallback"); } matchImagesUsingTensorFlow(imageUrl, word, i); }, ontimeout: function() { //console.log("Timed out. Using Fallback"); matchImagesUsingTensorFlow(imageUrl, word, i); }, }); } function matchImagesUsingTensorFlow(imageUrl, word, i) { try { let img = new Image(); img.crossOrigin = "Anonymous"; img.src = imageUrl; img.onload = () => { initializeTensorFlowModel().then(model => model.detect(img)) .then(function(predictions) { var predictionslen = predictions.length; for (var j = 0; j < predictionslen; j++) { if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0 && predictions[j].class.includesOneOf(word)) { qSelectorAll(TASK_IMAGE)[i].click(); break; } } img.removeAttribute("src"); selectedImageCount = selectedImageCount + 1; }); } } catch (err) { console.log(err.message); } } function matchImagesUsingTensorFlowMobileNet(imageUrl, word, i) { try { let img = new Image(); img.crossOrigin = "Anonymous"; img.src = imageUrl; img.onload = () => { initializeTensorFlowMobilenetModel().then(model => model.classify(img)) .then(function(predictions) { var predictionslen = predictions.length; for (var j = 0; j < predictionslen; j++) { var probability = 0.077; if (probabilityForObject.get(predictions[j].className)) { probability = probabilityForObject.get(predictions[j].className); } if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0 && predictions[j].className.includesOneOf(word) && predictions[j].probability > probability) { qSelectorAll(TASK_IMAGE)[i].click(); break; } } img.removeAttribute("src"); selectedImageCount = selectedImageCount + 1; }); } } catch (err) { console.log(err.message); } } // TODO: Generalize this logic // Identifying this based on the observation of the images seen // The actual way would be to scan the entire image to find the lake. // Mobilenet model in browser js identifies the lake but does not provide coordinates // to identify if it is horizontal or vertical function matchImageForVerticalRiver(imageUrl, word, i) { Jimp.read(imageUrl).then(function (data) { data.getBase64(Jimp.AUTO, async function (err, src) { var img = document.createElement("img"); img.setAttribute("src", src); await img.decode(); var imageHeight = img.height; var imageWidth = img.width; var cropHeight = imageHeight - 0.03*imageHeight; let url = src.replace(/^data:image\/\w+;base64,/, ""); let buffer = new Buffer(url, 'base64'); Jimp.read(buffer).then(function (data) { data.crop(0, cropHeight, imageWidth, imageHeight) .getBase64(Jimp.AUTO, async function (err, src) { var img = document.createElement("img"); img.src = src; await img.decode(); var c = document.createElement("canvas") c.width = img.width; c.height = img.height; var ctx = c.getContext("2d"); ctx.drawImage(img, 0, 0); var imageData = ctx.getImageData(0, 0, c.width, c.height); var data = imageData.data; var count = 0; //Multiple combinations and distances are required for accuracy for (let i = 0; i < data.length; i+= 4) { if( (data[i] < 140 && data[i+1] < 110 && data[i+2] > 80 && data[i+3] == 255) || (data[i] < 200 && data[i+1] < 200 && data[i+2] > 140 && data[i+3] == 255)){ count++; } } if(count > 0.001*(data.length/4) && count < data.length/8) { if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0) { qSelectorAll(TASK_IMAGE)[i].click(); } } img.removeAttribute("src"); selectedImageCount = selectedImageCount + 1; }); }); img.removeAttribute("src"); }); }); } // This approach is naive approch to store the images and retrieve // The accuracy is 100% as long as you store the selected images // Browser memory is used to store the images and gets cleared if you delete the browser cache and cookies // You may use this to store images in remote place and retrive for quick access // This approach is only used during urgent scenarios before training the images // Image differnce can also be done with the stored images to identify new image based on the existing if they are nearly equal function matchImagesUsingTrainer(imageUrl, word, i) { Jimp.read(imageUrl).then(function (data) { data.getBase64(Jimp.AUTO, async function (err, src) { var trainerInterval = setInterval(function(){ if (!qSelectorAll(IMAGE)[i] || !(qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) ){ clearInterval(trainerInterval); return; } if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0 && GM_getValue(src) && GM_getValue(src) == word) { console.log("Retrieved image from trainer"); selectedImageCount = selectedImageCount + 1; qSelectorAll(TASK_IMAGE)[i].click(); clearInterval(trainerInterval); return; } // Overriding Previously Stored values if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 1 && GM_getValue(src) && GM_getValue(src) != word) { console.log("Overriding image in the trainer"); selectedImageCount = selectedImageCount + 1; GM_setValue(src,word); console.log("Image Stored into database"); clearInterval(trainerInterval); return; } if (qSelectorAll(IMAGE)[i] && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 1 && !GM_getValue(src)) { selectedImageCount = selectedImageCount + 1; GM_setValue(src,word); console.log("Image Stored into database"); clearInterval(trainerInterval); return; } },5000); }); }); } //Function to sleep or delay async function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } //Different Models can be set later based on usecase //Ref Models: https://github.com/tensorflow/tfjs-models async function initializeTensorFlowModel() { if (!tensorFlowModel) { tensorFlowModel = await cocoSsd.load(); } return tensorFlowModel; } //MobileNet ssd model async function initializeTensorFlowMobilenetModel() { if (!tensorFlowMobileNetModel) { tensorFlowMobileNetModel = await mobilenet.load(); } return tensorFlowMobileNetModel; } //Initialize TesseractWorker function initializeTesseractWorker() { if (!worker) { worker = new Tesseract.TesseractWorker(); } } function clickImages(response, imageUrl, word, i) { try { if (response && response.responseText && (qSelectorAll(IMAGE)[i].style.background).includes(imageUrl) && qSelectorAll(TASK_IMAGE_BORDER)[i].style.opacity == 0) { var responseJson = JSON.parse(response.responseText); if (responseJson.identify && responseJson.identify.title && responseJson.identify.title.includesOneOf(word)) { qSelectorAll(TASK_IMAGE)[i].click(); } else if (responseJson.identify && responseJson.identify.entity && responseJson.identify.entity.includesOneOf(word)) { qSelectorAll(TASK_IMAGE)[i].click(); } else if (responseJson.identify && responseJson.identify.alternatives) { var alternatives = JSON.stringify(responseJson.identify.alternatives); var alternativesJson = JSON.parse(alternatives); for (var key in alternativesJson) { if (alternativesJson.hasOwnProperty(key)) { if ((alternativesJson[key].includesOneOf(word) || key.includesOneOf(word))) { qSelectorAll(TASK_IMAGE)[i].click(); break; } } } } else { //No Match found } selectedImageCount = selectedImageCount + 1; } else { //console.log("Using Fallback TensorFlow"); matchImagesUsingTensorFlow(imageUrl, word, i); } } catch (err) { //Using Fallback TensorFlow //console.log(err.message); //console.log("Using Fallback TensorFlow"); matchImagesUsingTensorFlow(imageUrl, word, i); } } function qSelectorAll(selector) { return document.querySelectorAll(selector); } function qSelector(selector) { return document.querySelector(selector); } async function getSynonyms(word) { USE_MOBILE_NET = false; USE_COLOUR_PATTERN = false; NEW_WORD_IDENTIFIED = false; //TODO: Format this to JSON string if (word == MOTORBUS || word == BUS) { word = ['bus', 'motorbus']; USE_MOBILE_NET = true; } else if (word == CAR) { word = ['=car', 'coupe', 'jeep', 'limo', 'sport utility vehicle', 'station wagon', 'hatchback', 'bumper car', 'modelT', 'electric battery', 'cruiser']; USE_MOBILE_NET = true; } else if (word == AIRPLANE) { word = ['airplane', 'plane', 'aircraft', 'aeroplane', 'hangar', 'Airdock', 'JumboJet', 'jetliner', 'stealth fighter', 'field artillery'] USE_MOBILE_NET = true; } else if (word == TRAIN) { word = ['train', 'rail', 'cable car', 'locomotive', 'subway station'] USE_MOBILE_NET = true; } else if (word == BOAT || word == SURFBOARD) { word = ['=boat', '=barge', 'houseboat', 'boathouse', 'speedboat', '=submarine', 'bobsled', 'catamaran', 'schooner', 'ocean liner', 'lifeboat', 'fireboat', 'yawl', 'pontoon', 'small boat', 'SnowBlower', 'Sea-coast', 'paddlewheel', 'paddle wheel', 'PaddleSteamer', 'Freighter', 'Sternwheeler', 'kayak', 'canoe', 'deck', 'DockingFacility', 'surfboard', '=ship', '=cruise', 'watercraft', 'sail', 'canvas', '=raft'] USE_MOBILE_NET = true; } else if (word == BICYCLE) { word = ['bicycle-built-for-two', 'tandem bicycle', 'bicycle', 'tricycle', 'mountain bike', 'AcceleratorPedal', 'macaw', 'knot'] USE_MOBILE_NET = true; } else if (word == MOTORCYCLE) { word = ['moped', 'motor scooter', 'scooter', 'motorcycle', 'windshield', 'dashboard'] USE_MOBILE_NET = true; } else if (word == TRUCK) { word = ['truck', 'cargocontainer', 'bazooka'] USE_MOBILE_NET = true; } else if (word == TRIMARAN || word == SPEEDBOAT || word == SEAPLANE) { word = ['spatula', 'can opener', 'tin opener', 'monitor', 'screen', 'stretcher', 'printer', 'nail', 'mousetrap', 'TRIMARAN', 'space shuttle', 'ski', 'rotisserie', 'geyser', 'plate rack'] USE_MOBILE_NET = true; } else if (word.includesOneOf(LIVING_ROOM_TYPES)) { word = ['bed', 'couch', 'chair', 'potted plant', 'dining table', 'clock', 'tv', 'book'] } else if (word == ZEBRA) { word = ['zebra'] } else if (word == CAT) { word = ['cat'] USE_MOBILE_NET = true; } else if (word == DOG) { word = ['dog'] } else if (word == VALLEY || word == VERTICAL_RIVER){ word = ['alp','volcano'] USE_COLOUR_PATTERN = true; } else { NEW_WORD_IDENTIFIED = true; console.log("Word does not match. New type identified::" + word); } return word } function isHidden(el) { return (el.offsetParent === null) } if (window.location.href.includes("checkbox")) { var checkboxInterval = setInterval(function() { if (!qSelector(CHECK_BOX)) { //Wait until the checkbox element is visible } else if (qSelector(CHECK_BOX).getAttribute(ARIA_CHECKED) == "true") { clearInterval(checkboxInterval); } else if (!isHidden(qSelector(CHECK_BOX)) && qSelector(CHECK_BOX).getAttribute(ARIA_CHECKED) == "false") { qSelector(CHECK_BOX).click(); } else { return; } }, 5000); } else { try { await initializeTesseractWorker(); await initializeTensorFlowModel(); await initializeTensorFlowMobilenetModel(); selectImages(); } catch (err) { console.log(err); console.log("Tesseract could not be initialized"); } } function selectImagesAfterDelay(delay) { setTimeout(function() { selectImages(); }, delay * 1000); } function triggerEvent(el, type) { var e = document.createEvent('HTMLEvents'); e.initEvent(type, false, true); el.dispatchEvent(e); } function triggerMouseEvent(el, type) { var e = document.createEvent('MouseEvent'); e.initEvent(type, false, true); el.dispatchEvent(e); } // Small hack to select the nodes function unsure(targetNodeText) { var targetNode = Array.from(qSelectorAll('div')) .find(el => el.textContent === targetNodeText); //Works for now //TODO: Select clothing //TODO: Draw boxes around images if (targetNode) { triggerMouseEvent(targetNode, 'mousedown'); triggerMouseEvent(targetNode, 'mouseup'); if (qSelector(SUBMIT_BUTTON)) { qSelector(SUBMIT_BUTTON).click(); } } return selectImagesAfterDelay(1); } function getUrlFromString(urlString) { var imageUrl = urlString.substring( urlString.indexOf('"') + 1, urlString.lastIndexOf('"') ); if (!imageUrl || !imageUrl.includes("https")) { return 0; } return imageUrl; } function getImageList() { var imageList = []; if (qSelectorAll(IMAGE).length > 0) { for (var i = 0; i < 9; i++) { var urlString = qSelectorAll(IMAGE)[i].style.background; var imageUrl = getUrlFromString(urlString); if (imageUrl == 0) { //console.log("Image url is empty"); return imageList; } imageList[i] = imageUrl; } } return imageList; } function waitUntilImageSelection() { var imageIntervalCount = 0; var imageInterval = setInterval(function() { imageIntervalCount = imageIntervalCount + 1; if (selectedImageCount == 9) { clearInterval(imageInterval); if (qSelector(SUBMIT_BUTTON)) { qSelector(SUBMIT_BUTTON).click(); } return selectImagesAfterDelay(5); } else if (imageIntervalCount > 8) { clearInterval(imageInterval); return selectImages(); } else if(selectedImageCount > 2 && MATCH_IMAGES_USING_TRAINER && NEW_WORD_IDENTIFIED && imageIntervalCount > 4){ clearInterval(imageInterval); if (qSelector(SUBMIT_BUTTON)) { qSelector(SUBMIT_BUTTON).click(); } return selectImagesAfterDelay(5); } else if(MATCH_IMAGES_USING_TRAINER && NEW_WORD_IDENTIFIED && imageIntervalCount > 6){ clearInterval(imageInterval); if (qSelector(SUBMIT_BUTTON)) { qSelector(SUBMIT_BUTTON).click(); } return selectImagesAfterDelay(5); }else{ } }, 3000); } function waitForImagesToAppear() { var checkImagesSelectedCount = 0; var waitForImagesInterval = setInterval(function() { checkImagesSelectedCount = checkImagesSelectedCount + 1; if (qSelectorAll(IMAGE) && qSelectorAll(IMAGE).length == 9) { clearInterval(waitForImagesInterval); return selectImages(); } else if (checkImagesSelectedCount > 60) { clearInterval(waitForImagesInterval); } else if (qSelector(CHALLENGE_INPUT_FIELD) && qSelector(NO_SELECTION).getAttribute(ARIA_HIDDEN) != true) { clearInterval(waitForImagesInterval); return imageUsingOCR(); } else { //TODO: Identify Objects for the following (Ex: bed,chair,table etc) //Ref for clothing: https://www.youtube.com/watch?v=yWwzFnAnrLM, https://www.youtube.com/watch?v=FiNglI1wRNk,https://www.youtube.com/watch?v=oHAkK_9UCQ8 var targetNodeList = ["Yes", "3 or more items of furniture", "Equipped space or room", "Photo is clean, no watermarks, logos or text overlays", "An interior photo of room", "Unsure", "Photo is sharp"]; for (var j = 0; j < targetNodeList.length; j++) { var targetNode = Array.from(qSelectorAll('div')) .find(el => el.textContent === targetNodeList[j]); if (targetNode) { //console.log("Target Node Found"); clearInterval(waitForImagesInterval); return unsure(targetNodeList[j]); } } } }, 5000); } //TODO: Convert Image to base64 to avoid multiple calls function preProcessImage(base64Image, imageUrl) { //Darken and Brighten Jimp.read(base64Image).then(function(data) { data.color([ { apply: 'darken', params: [20] } ]).color([ { apply: 'brighten', params: [20] } ]) .greyscale() .getBase64(Jimp.AUTO, function(err, src) { var img = document.createElement("img"); img.setAttribute("src", src); worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) { //Remove Image After recognizing img.removeAttribute("src"); //If null change to other methods if (data && data.text && data.text.length > 0) { inputChallenge(postProcessImage(data), imageUrl); return selectImages(); } else { preProcessImageMethod2(base64Image, imageUrl); } }); }); }); } function preProcessImageMethod2(base64Image, trimageUrl) { //Multi Contrast darken and brighten Jimp.read(base64Image).then(function(data) { data.color([ { apply: 'darken', params: [20] } ]).contrast(1).color([ { apply: 'brighten', params: [20] } ]).contrast(1).greyscale().getBase64(Jimp.AUTO, function(err, src) { var img = document.createElement("img"); img.setAttribute("src", src); worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) { //Remove Image After recognizing img.removeAttribute("src"); if (data && data.text && data.text.length > 0) { inputChallenge(postProcessImage(data), imageUrl); return selectImages(); } else { preProcessImageMethod3(base64Image, imageUrl); } }); }); }); } function preProcessImageMethod3(base64Image, imageUrl) { //Multi Contrast only brighten Jimp.read(base64Image).then(function(data) { data.contrast(1).color([{ apply: 'brighten', params: [20] } ]) .contrast(1) .greyscale() .getBase64(Jimp.AUTO, function(err, src) { var img = document.createElement("img"); img.setAttribute("src", src); worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) { //Remove Image After recognizing img.removeAttribute("src"); if (data && data.text && data.text.length > 0) { inputChallenge(postProcessImage(data), imageUrl); return selectImages(); } else { preProcessImageMethod4(base64Image, imageUrl); } }); }); }); } function preProcessImageMethod4(base64Image, imageUrl) { //Resize the image Jimp.read(base64Image).then(function(data) { data.resize(256, Jimp.AUTO) .quality(60) // set JPEG quality .greyscale() // set greyscale .getBase64(Jimp.AUTO, function(err, src) { var img = document.createElement("img"); img.setAttribute("src", src); worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) { //Remove Image After recognizing img.removeAttribute("src"); inputChallenge(postProcessImage(data), imageUrl); return selectImages(); }); }); }); } function postProcessImage(data) { var filterValues = ['\n', '{', '}', '[', ']']; for (var i = 0; i < filterValues.length; i++) { data.text = data.text.replaceAll(filterValues[i], ""); } return data; } // Using Tesseract to recognize images function imageUsingOCR() { try { //console.log("Image using OCR"); var urlString = qSelector(IMAGE_FOR_OCR).style.background; var imageUrl = getUrlFromString(urlString); if (imageUrl == 0) { return selectImagesAfterDelay(1); } Jimp.read(imageUrl).then(function(data) { data.getBase64(Jimp.AUTO, function(err, src) { var img = document.createElement("img"); img.setAttribute("src", src); var base64Image = img.src; preProcessImage(base64Image, imageUrl); })}); } catch (err) { console.log(err.message); return selectImagesAfterDelay(1); } } async function convertTextToImage(text) { //Convert Text to image var canvas = document.createElement("canvas"); var textLength = text.length; canvas.width = 60 * textLength; canvas.height = 80; var ctx = canvas.getContext('2d'); ctx.font = "30px Arial"; ctx.fillText(text, 10, 50); var img = document.createElement("img"); img.src = canvas.toDataURL(); return img; } async function convertImageToText(img) { await initializeTesseractWorker(); //Convert Image to Text var text = ""; await worker.recognize(img, LANGUAGE_FOR_OCR).then(function(data) { text = data.text; // console.log("Recognized Text::" + text); }); return text.trim(); } function areExampleImageUrlsChanged() { var prevExampleUrls = exampleImageList; currentExampleUrls = []; if (qSelectorAll(CHALLENGE_IMAGE).length > 0) { for (let i = 0; i < qSelectorAll(CHALLENGE_IMAGE).length; i++) { var urlString = qSelectorAll(CHALLENGE_IMAGE)[i].style.background; var imageUrl = getUrlFromString(urlString); if (imageUrl == 0) { console.log("Image url is empty, Retrying..."); return true; } currentExampleUrls[i] = imageUrl; } } if (prevExampleUrls.length != currentExampleUrls.length) { return true; } for (let i = 0; i < currentExampleUrls.length; i++) { if (prevExampleUrls[i] != currentExampleUrls[i]) { return true; } } return false; } async function identifyObjectsFromImages(imageUrlList) { identifiedObjectsList = []; for (let i = 0; i < imageUrlList.length; i++) { try { let img = new Image(); img.crossOrigin = "Anonymous"; img.src = imageUrlList[i]; img.onload = () => { initializeTensorFlowModel().then(model => model.detect(img)) .then(function(predictions) { let predictionslen = predictions.length; let hashSet = new Set(); for (let j = 0; j < predictionslen; j++) { hashSet.add(predictions[j].class); } hashSet.forEach((key) => { identifiedObjectsList.push(key); }); img.removeAttribute("src"); if (i == imageUrlList.length - 1) { identifyObjectsFromImagesCompleted = true; } }) } } catch (e) { console.log(e); } } } async function identifyObjectsFromImagesUsingMobileNet(imageUrlList) { identifiedObjectsList = []; for (let i = 0; i < imageUrlList.length; i++) { try { let img = new Image(); img.crossOrigin = "Anonymous"; img.src = imageUrlList[i]; img.onload = () => { initializeTensorFlowMobilenetModel().then(model => model.classify(img)) .then(function(predictions) { let predictionslen = predictions.length; let hashSet = new Set(); for (let j = 0; j < predictionslen; j++) { if(predictions[j].className.includes(",")){ var multiPredictions = predictions[j].className.split(','); for(let k=0; k< multiPredictions.length;k++){ hashSet.add(multiPredictions[k].trim()); } }else{ hashSet.add(predictions[j].className); } } hashSet.forEach((key) => { identifiedObjectsList.push(key); }); img.removeAttribute("src"); if (i == imageUrlList.length - 1) { identifyObjectsFromImagesCompleted = true; } }) } } catch (e) { console.log(e); } } } async function getWordFromIdentifiedObjects(identifiedObjectsList) { var hashMap = new Map(); for (var i = 0; i < identifiedObjectsList.length; i++) { if (hashMap.has(identifiedObjectsList[i])) { hashMap.set(identifiedObjectsList[i], hashMap.get(identifiedObjectsList[i]) + 1) } else { hashMap.set(identifiedObjectsList[i], 1) } } var maxCount = 0, objectKey = -1; await hashMap.forEach((value, key) => { if (maxCount < value && (key.equalsOneOf(TRANSPORT_TYPES) || key.equalsOneOf(LIVING_ROOM_TYPES) || key.equalsOneOf(ANIMAL_TYPES)|| key == VALLEY)) { objectKey = key; maxCount = value; } }); return objectKey; } function inputChallenge(data, imageUrl) { try { if ((qSelector(IMAGE_FOR_OCR).style.background).includes(imageUrl)) { console.log(data.text); var targetNode = qSelector(CHALLENGE_INPUT_FIELD); targetNode.value = data.text.replaceAll("\n", ""); var challengeInput = qSelector(CHALLENGE_INPUT); triggerEvent(challengeInput, 'input'); // Set a timeout if you want to see the text qSelector(SUBMIT_BUTTON).click(); } } catch (err) { console.log(err.message); } } async function identifyWordFromExamples() { var word = -1; if (areExampleImageUrlsChanged()) { exampleImageList = currentExampleUrls; if (exampleImageList.length == 0) { return -1; } identifyObjectsFromImages(exampleImageList); while (!identifyObjectsFromImagesCompleted) { await delay(2000) } identifyObjectsFromImagesCompleted = false; word = await getWordFromIdentifiedObjects(identifiedObjectsList); //Word has not been identified yet, use mobile net to recognize images if (word == -1) { //Initialiaze MobileNet Model await initializeTensorFlowMobilenetModel(); identifyObjectsFromImagesUsingMobileNet(exampleImageList); while (!identifyObjectsFromImagesCompleted) { await delay(2000) } identifyObjectsFromImagesCompleted = false; word = getWordFromIdentifiedObjects(identifiedObjectsList); } return word; } else { return getWordFromIdentifiedObjects(identifiedObjectsList); } return word; } var prevObject = ""; function isObjectChanged() { if (!prevObject && qSelector(PROMPT_TEXT)) { prevObject = qSelector(PROMPT_TEXT).innerText; return true; } if (prevObject && qSelector(PROMPT_TEXT) && prevObject == qSelector(PROMPT_TEXT).innerText) { return false; } return true; } async function identifyWord() { var word = -1; try { if (window.location.href.includes('&hl=en') || (ENABLE_DEFAULT_LANGUAGE && DEFAULT_LANGUAGE == LANG_ENGLISH)) { word = qSelector(PROMPT_TEXT) ? qSelector(PROMPT_TEXT).innerText : word; if (word && (word.includes(SENTENCE_TEXT_A) || word.includes(SENTENCE_TEXT_AN))) { word = word.replace(SENTENCE_TEXT_A, ''); word = word.replace(SENTENCE_TEXT_AN, ''); } if (word.equalsOneOf(TRANSPORT_TYPES) || word == VERTICAL_RIVER) { return word; } else { //Using OCR on Text for accurate result console.log("New word or different cyrillic"); var img = await convertTextToImage(word); word = await convertImageToText(img); word = word.replace(SENTENCE_TEXT_A, ''); word = word.replace(SENTENCE_TEXT_AN, ''); if (word.equalsOneOf(TRANSPORT_TYPES) || word == VERTICAL_RIVER) { return word; } else { if(MATCH_IMAGES_USING_TRAINER){ word = qSelector(PROMPT_TEXT) ? qSelector(PROMPT_TEXT).innerText : -1; if(word){ img = await convertTextToImage(word); word = await convertImageToText(img); } return word; }else{ word = await identifyWordFromExamples(); } } } } else { //If word is not english //Identify Images from Example word = await identifyWordFromExamples(); } } catch (e) { console.log(e); } return word; } var prevWord = ""; async function selectImages() { if (ENABLE_DEFAULT_LANGUAGE) { for (let i = 0; i < qSelectorAll(LANGUAGE_SELECTOR).length; i++) { if (qSelectorAll(LANGUAGE_SELECTOR)[i].innerText == DEFAULT_LANGUAGE) { document.querySelectorAll(LANGUAGE_SELECTOR)[i].click(); await delay(1000); } } } if (qSelectorAll(IMAGE) && qSelectorAll(IMAGE).length == 9 && qSelector(NO_SELECTION).getAttribute(ARIA_HIDDEN) != true) { selectedImageCount = 0; try { if (isObjectChanged()) { prevWord = await identifyWord(); } var word = prevWord; if (word == -1 && skipCount >= MAX_SKIPS) { console.log("Max Retries Attempted. Captcha cannot be solved"); return; } else if (word == -1 && skipCount < MAX_SKIPS) { skipCount++; if (qSelector(SUBMIT_BUTTON)) { qSelector(SUBMIT_BUTTON).click(); } return selectImagesAfterDelay(5); } else { //Get Synonyms for the word word = await getSynonyms(word); //console.log("words are::" + word); } } catch (err) { console.log(err.message); return selectImagesAfterDelay(5); } var imageList = []; try { imageList = getImageList(); if (imageList.length != 9) { //console.log("Waiting"); // Image containers are visible but there are no urls in the image // Skip the image if (qSelector(SUBMIT_BUTTON)) { qSelector(SUBMIT_BUTTON).click(); } return selectImagesAfterDelay(5); } } catch (err) { console.log(err.message); return selectImagesAfterDelay(5); } //Identifying word for seaplane and matching images //TODO: Refactor Code to combine different models or use only one model based on accuracy if(word && word != -1 && MATCH_IMAGES_USING_TRAINER && NEW_WORD_IDENTIFIED){ for (let i = 0; i < 9; i++) { matchImagesUsingTrainer(imageList[i], word, i); } }else if(word && word != -1 && USE_COLOUR_PATTERN){ for (let i = 0; i < 9; i++) { matchImageForVerticalRiver(imageList[i], word, i); } }else if (word && word != -1 && USE_MOBILE_NET) { for (let i = 0; i < 9; i++) { matchImagesUsingTensorFlowMobileNet(imageList[i], word, i); } } else if (word && word != -1) { for (var i = 0; i < 9; i++) { if (ENABLE_TENSORFLOW) { matchImagesUsingTensorFlow(imageList[i], word, i); } else { matchImages(imageList[i], word, i); } } } waitUntilImageSelection(); } else { waitForImagesToAppear(); } } })();