[KissAnime] Captcha Solver

Saves initial responses to KissAnime captcha and auto-selects images if it knows the answer.

Install this script?
Author's suggested script

You may also like [KissAnime] Beta Default Server.

Install this script
// ==UserScript==
// @name         [KissAnime] Captcha Solver
// @namespace    https://greasyfork.org/en/users/193865-westleym
// @author       WestleyM
// @version      2019.4.3
// @icon         http://kissanime.ru/Content/images/favicon.ico
// @description  Saves initial responses to KissAnime captcha and auto-selects images if it knows the answer.
// @grant        none
// @include      *://kissanime.ru/Special/AreYouHuman2*
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// ==/UserScript==

function main() {
    //Variable declarations
    var currentVersion = "2018.10.15";
    var installText = "Thank you for installing [KissAnime] Captcha Solver!";
    var updateText = "Updated to version 2019.4.3.  I no longer actively update this script.  I can't guarantee support if KA changes things again.\nThe best way to reach me is on Reddit @WarriorSolution";
    var $ = window.jQuery;
    var formVerify = document.getElementById("formVerify1");
    var words = [], undefinedWords = [], unknownWords = [], knownWords = [],
        imageSrc = [], clickImage = [], imageData = [], imageElements = [], multiImageFlag = [];
    var matchFound = 0, count = 0, impExpFlag = 0, askedForHelp = 0, PHObjFlag = 0;
    var wordImagePairs = {}, wordsObj = {}, imageObj = {}, clickedImgs = {}, placeholderObjOne = {}, placeholderObjTwo = {};
    var dataURL = "";
    var impExpButton, inputSubmit, exportButton,
        firstDiv, PElements, thirdPElement, alertBoxDiv,
        alertBoxText, importExport, inputJSON, lineSeparator,
        exportDirections, exportBox; //Variables used for created HTML elements

    if (formVerify === null) {
        var link = document.getElementsByTagName("a");
        link = link[0];
        if (localStorage.getItem("KCS-lastDescriptions") != null) {
            wordsObj = JSON.parse(localStorage.getItem("KCS-lastDescriptions"));
            localStorage.removeItem(wordsObj.firstWord);
            localStorage.removeItem(wordsObj.secondWord);
            localStorage.removeItem("KCS-lastDescriptions");
            console.log("Deleted the last two entries.");
        }
        console.log("Redirecting page. . . .");
        link.click();
    }


    if (formVerify != null) { //User is on the regular captcha page
        //Alerts for initial install or update of the script
        if (localStorage.getItem("KCS-version") === null && localStorage.getItem("version") === null) { messagePusher("install"); }
        if (localStorage.getItem("KCS-version") != currentVersion && localStorage.getItem("KCS-version") != null) { messagePusher("update"); }
        if (localStorage.getItem("KCS-version") === null && localStorage.getItem("version") != null) { messagePusher("update"); }

        //Image onclick events
        imageElements = $("#formVerify1").find("img").toArray();
        imageElements.forEach(function(currentImage, imageIndex) { currentImage.onclick = function() { onClickEvents("image", currentImage, imageIndex); } });

        //Create custom HTML
        customHTML();

        //Import/Export onclick function calls
        impExpButton.onclick = function() { onClickEvents("impExpButton") };
        inputSubmit.onclick = function() { onClickEvents("inputSubmit") };
        exportButton.onclick = function() { onClickEvents("exportButton") };

        //Avoid conflicts, start main processes
        this.$ = this.jQuery = jQuery.noConflict(true);
        $(document).ready(function() {
            wordGrabber();
            unknownWordGrabber();
            knownWordGrabber();
            imageGrabber();
            clickImages();

            console.log("Unknown words: " + unknownWords);
            console.log("Known words: " + knownWords);
            if (unknownWords[0] != undefined) { //Ask for help with the first unknown word
                askForHelp(unknownWords[0]);
            }
        });
    }



    //Functions
    function askForHelp(word) { //Asks you to select an answer when the script doesn't know.
        alertBoxText.innerText = "Please select image: " + word;
        localStorage.setItem("KCS-helpWord", word);
    }

    function unknownWordGrabber() { //Finds the words that the script doesn't know the answer to
        words.forEach(function(word) {
            if(!localStorage.getItem("KCS-" + word)) { //If the solution isn't found in the local storage, it will be added to the "unknownWords" array
                unknownWords.push(word);
            }
        });
    }

    function knownWordGrabber() { //Finds the words that the script knows the answer to
        words.forEach(function(word) {
            if(localStorage.getItem("KCS-" + word)) { //If solution is found in the local storage, it will be added to the "knownWords" array
                knownWords.push(word);
            }
        });
    }

    function wordGrabber() { //Grabs span elements that are children of the "formVerify" form.  This will include the two sections saying what to select.  Ex: "cat, glasses, 0"
        var pElements = $("#formVerify1").find("p").toArray();
        var finalPElement, wordElements;

        pElements.forEach(function(pElement) { //Grabs the p element that contains 2 span elements in it.
            if ($(pElement).find("span").toArray().length === 2) {
                wordElements = $(pElement).find("span").toArray();
            }
        });
        words = [wordElements[0].innerText, wordElements[1].innerText];

        //Saves the descriptions to local Storage
        var lastDescriptions = { "firstWord":wordElements[0].innerText, "secondWord":wordElements[1].innerText };
        var DescJSON = JSON.stringify(lastDescriptions);
        localStorage.setItem("KCS-lastDescriptions", DescJSON);
    }

    function imageGrabber() {
        imageElements.forEach(function(image, index) {
            var objKey = "image" + index.toString();
            var imageData = convertToDataUrl(image);
            imageData = minimiseDataUrl(minimiseDataUrl(minimiseDataUrl(imageData, 5), 4), 3);
            imageObj[objKey] = imageData;
        });
    }

    function convertToDataUrl(img) {
        var canvas = document.createElement("canvas");
        canvas.width = img.width;
        canvas.height = img.height;
        var ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        var dataURL = canvas.toDataURL("image/png");
        return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
    }

    function minimiseDataUrl(dataUrl,jump) {
        var a = "";
        for(var i = 0; i < dataUrl.length; i=i+jump) {
            a += dataUrl.charAt(i);
        }
        return a;
    }

    function clickImages() {
        knownWords.forEach(function(word) {
            var i = 0;
            for (var key in imageObj) {
                if (localStorage.getItem("KCS-" + word) == imageObj[key]) {
                    $("[indexValue='" + i + "']").click();
                    break;
                } else if (i === Object.keys(imageObj).length-1) {
                    var multiImageDesc = localStorage.getItem("KCS-" + word);
                    var foundFlag = 0;
                    try {
                        JSON.parse(multiImageDesc);
                        for (var j = 0; j < Object.keys(multiImageDesc).length; j++) {
                            if (multiImageDesc[j] === imageObj[key]) {
                                console.log("Description with multiple images found and clicked: " + word);
                                $("[indexValue='" + i + "']").click();
                                foundFlag = 1;
                            }
                        }
                    }
                    catch(err) {}
                    if (foundFlag === 0) {
                        console.log("Description with multiple images found.  Solution unknown: " + word);
                        multiImageFlag.push(word);
                        unknownWords.push(word);
                        knownWords.splice(knownWords.indexOf(word), 1);
                    }
                }
                i++;
            }
        });
    }

    function convertSolutions() {
        var tempVarKey = "";
        var tempVarDesc = "";
        for (var i = 0; i < localStorage.length; i++) {
            if (localStorage.key(i) != "KCS-helpWord" && localStorage.key(i) != "KCS-lastDescriptions" && localStorage.key(i) != "KCS-version") {
                tempVarKey = localStorage.key(i);
                tempVarKey = tempVarKey.replace(/KCS-/g, "");
                tempVarDesc = localStorage.getItem(localStorage.key(i));
                localStorage.removeItem(localStorage.key(i));
                localStorage.setItem("KCS-" + tempVarKey, tempVarDesc);
            }
        }
    }

    function removeBrokenSolutions() {
        for (var i = 0; i < localStorage.length; i++) {
            if (localStorage.getItem(localStorage.key(i))[0] === "[" || localStorage.getItem(localStorage.key(i)) === undefined || localStorage.getItem(localStorage.key(i)) === "undefined") {
                localStorage.removeItem(localStorage.key(i));
            }
        }
    }

    function messagePusher(type) {
        switch(type) {
            case "install":
                console.log(installText);
                localStorage.removeItem("version");
                localStorage.removeItem("lastDescriptions");
                localStorage.removeItem("helpWord");
                localStorage.setItem("KCS-version", currentVersion);
                break;
            case "update":
                //alert("(You will only see this message once per update)\n\n" + updateText);
                localStorage.removeItem("version");
                localStorage.removeItem("lastDescriptions");
                localStorage.removeItem("helpWord");
                localStorage.setItem("KCS-version", currentVersion);
                convertSolutions();
                removeBrokenSolutions();
                break;
        }
    }

    function customHTML() {
        //Message box
        firstDiv = $("#formVerify1").find("div").toArray()[0];
        firstDiv.style.cssText = "width:100%;"; //The box holding the information at the top was not wide enough originally

        PElements = $(firstDiv).find("p").toArray();
        if (PElements.length === 2) {
            PElements[0].style.cssText = "opacity:0; height:0px; width:100%; line-height:0px; font-size:0px;";
        }
        if (PElements.length === 3) {
            PElements[0].style.cssText = "display: none;";
            PElements[1].style.cssText = "opacity:0; height:0px; width:100%; line-height:0px; font-size:0px;";
        }

        thirdPElement = PElements[PElements.length-1];
        thirdPElement.style.cssText = "opacity:0; height:0px; width:100%; line-height:0px; font-size:0px;"; //Hides where it lists both selection choices.  This is to insure users select the images in the correct order.

        alertBoxDiv = document.createElement("div"); //Creation of div element which will contain the below text element
        alertBoxDiv.style.cssText = "background:#518203; color:white; height:30px; width:100%; line-height:30px; text-align:center;";

        alertBoxText = document.createElement("h3"); //Creation of text element which will say the descriptions of images the script doesn't know the answer to
        alertBoxText.innerText = "Checking data. . . .";
        alertBoxText.style.cssText = "background:#518203; color:white; height:100%; width:100%; text-align:center; font-size: 20px; margin-top:0px;";

        alertBoxDiv.insertAdjacentElement("afterbegin", alertBoxText); //Inserting "alertBoxText" into "alertBoxDiv" at the top
        thirdPElement.insertAdjacentElement("afterend", alertBoxDiv); //Placing "alertBoxDiv" at the end of "mainBlock"

        //Import/Export area
        importExport = document.createElement("div");
        importExport.style.cssText = "display:block; background: #111111; color:white; width:970px; padding:2px; text-align:center; margin-left:auto; margin-right:auto; border:1px solid #2f2f2f;";
        importExport.id = "importExport";

        impExpButton = document.createElement("p");
        impExpButton.style.cssText = "background:#518203; color:white; height:15px; width:960px; margin-top:5px; margin-bottom:5px; text-align:center; font-size: 15px; padding:5px; cursor:pointer;";
        impExpButton.innerText = "[+] Solution List Importing/Exporting";
        impExpButton.id = "impExpButton";

        inputJSON = document.createElement("input");
        inputJSON.type = "text";
        inputJSON.name = "JSON input";
        inputJSON.id = "inputJSON";
        inputJSON.placeholder = "Paste solution here";
        inputJSON.style.cssText = "display:none; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px;";

        inputSubmit = document.createElement("div");
        inputSubmit.style.cssText = "display:none; background:#518203; color:white; height:20px; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px; border:1px solid #5a5a5a; cursor:pointer;";
        inputSubmit.innerText = "Submit";
        inputSubmit.id = "inputSubmit";

        lineSeparator = document.createElement("div");
        lineSeparator.style.cssText = "display:none; background:#5f5f5f; height:3px; width:100%; margin-left:auto; margin-right:auto; margin-bottom:5px;";
        lineSeparator.id = "lineSeparator";

        exportButton = document.createElement("div");
        exportButton.style.cssText = "display:none; background:#518203; color:white; height:20px; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px; border:1px solid #5a5a5a; cursor:pointer;";
        exportButton.innerText = "Export list";
        exportButton.id = "exportButton";

        exportDirections = document.createElement("div");
        exportDirections.style.cssText = "display:none; background:#518203; color:white; height:20px; width:50%; margin-left:auto; margin-right:auto; margin-bottom:5px; border:1px solid #5a5a5a;";
        exportDirections.innerText = "Copy the below data: (triple click to select all)";
        exportDirections.id = "exportDirections";

        exportBox = document.createElement("p");
        exportBox.style.cssText = "display:none; #111111; color:white; width:75%; margin-left:auto; margin-right:auto; margin-top:0px; margin-bottom:5px; text-align:center; font-size:10px; border:1px solid #2f2f2f; word-wrap: break-word; overflow:auto; max-height:500px;";
        exportBox.innerText = "";
        exportBox.id = "exportBox";

        importExport.insertAdjacentElement("afterbegin", impExpButton);
        importExport.insertAdjacentElement("beforeend", inputSubmit);
        inputSubmit.insertAdjacentElement("afterend", lineSeparator);
        lineSeparator.insertAdjacentElement("afterend", exportButton);
        exportButton.insertAdjacentElement("afterend", exportDirections);
        exportDirections.insertAdjacentElement("afterend", exportBox);
        impExpButton.insertAdjacentElement("afterend", inputJSON);
        document.getElementById("containerRoot").insertAdjacentElement("afterend", importExport);
    }

    function onClickEvents(clickedItem, clickedImage, imageIndexValue) {
        switch(clickedItem) {
            case "impExpButton":
                if (impExpFlag === 0) {
                    impExpButton.innerText = "[-] Solution List Importing/Exporting";
                    inputJSON.style.display = "block";
                    inputSubmit.style.display = "block";
                    lineSeparator.style.display = "block";
                    exportButton.style.display = "block";
                    impExpFlag = 1;
                } else {
                    impExpButton.innerText = "[+] Solution List Importing/Exporting";
                    inputJSON.style.display = "none";
                    inputSubmit.style.display = "none";
                    lineSeparator.style.display = "none";
                    exportButton.style.display = "none";
                    exportDirections.style.display = "none";
                    exportBox.style.display = "none";
                    impExpFlag = 0;
                }
                break;
            case "exportButton":
                //Grab data from local storage and convert to JSON string
                for (var i = 0; i < localStorage.length; i++) {
                    if (localStorage.key(i) != "KCS-helpWord" && localStorage.key(i) != "KCS-lastDescriptions" && localStorage.key(i) != "KCS-version") {
                        wordImagePairs[localStorage.key(i)] = localStorage.getItem(localStorage.key(i));
                    }
                }
                var wordImagePairsJSON = JSON.stringify(wordImagePairs);
                exportBox.innerText = wordImagePairsJSON;
                exportDirections.style.display = "block";
                exportBox.style.display = "block";
                break;
            case "inputSubmit":
                var inputData = inputJSON.value;
                var currentTemp = "";
                var oldListLength = localStorage.length.toString();
                try {
                    var newCaptchaData = JSON.parse(inputData);
                    Object.keys(newCaptchaData).forEach(function(current) {
                        currentTemp = current.replace(/KCS-/g, ""); //Allows for compatibility between old export lists and new ones.
                        localStorage.setItem("KCS-" + currentTemp, newCaptchaData[current]);
                    });
                    inputSubmit.innerText = "Submitted successfully!  Old/new/changed solutions: " + oldListLength + "/" + localStorage.length.toString() + "/" + Object.keys(newCaptchaData).length;
                    console.log("Solution list has been updated.");
                }
                catch(err) {
                    inputSubmit.innerText = "There was an issue.  Check the console.";
                    console.log("Issue with list upload: " + err);
                }
                removeBrokenSolutions();
                convertSolutions();
                break;
            case "image":
                if ($(clickedImage).attr("class") === "imgCapSelect") {
                    clickedImgs[localStorage.getItem("KCS-helpWord")] = imageIndexValue;
                } else {
                    words.forEach(function(word) {
                        if (imageIndexValue === clickedImgs[word]) {
                            delete clickedImgs[word];
                        }
                    });
                }
                if (Object.keys(clickedImgs).length === words.length) {
                    for (var key in clickedImgs) {
                        if (key !== multiImageFlag[0] && key !== multiImageFlag[1]) {
                            localStorage.setItem("KCS-" + key, imageObj["image" + clickedImgs[key].toString()]);
                        } else {
                            var currentSolution = localStorage.getItem(key);
                            try {
                                JSON.parse(currentSolution);
                                currentSolution[Object.keys(currentSolution).length] = imageObj["image" + clickedImgs[key].toString()];
                            }
                            catch(err) {
                                if (PHObjFlag === 0) {
                                    placeholderObjOne[0] = currentSolution;
                                    placeholderObjOne[1] = imageObj["image" + clickedImgs[key].toString()];
                                    currentSolution = placeholderObjOne;
                                    PHObjFlag = 1;
                                } else if (PHObjFlag === 1) {
                                    placeholderObjTwo[0] = currentSolution;
                                    placeholderObjTwo[1] = imageObj["image" + clickedImgs[key].toString()];
                                    currentSolution = placeholderObjTwo;
                                    PHObjFlag = 2;
                                }
                            }
                            JSON.stringify(currentSolution);
                            localStorage.setItem("KCS-" + key, currentSolution);
                        }
                    }
                    alertBoxText.innerText = "Selections complete.  Loading next page. . . .";
                }
                if (Object.keys(clickedImgs).length < words.length) {
                    words.forEach(function(word, index) {
                        if (clickedImgs[word] === undefined && askedForHelp === 0) {
                            askForHelp(word);
                            askedForHelp = 1;
                        }
                    });
                    askedForHelp = 0;
                }
        }
    }
}

main();